226void VuoLog_statusF(
const char *moduleName,
const char *file,
const unsigned int linenumber,
const char *function,
const char *format, ...)
228 static dispatch_once_t statusInitialized = 0;
229 static dispatch_queue_t statusQueue;
230 dispatch_once(&statusInitialized, ^{
231 statusQueue = dispatch_queue_create(
"VuoLogStatus", NULL);
234 char *message =
nullptr;
238 va_start(args, format);
239 vasprintf(&message, format, args);
243 dispatch_sync(statusQueue, ^{
244 if (VuoCrashReport.signature)
245 free(VuoCrashReport.signature);
248 VuoCrashReport.signature = message;
250 VuoCrashReport.signature =
nullptr;
344void VuoLog(
const char *moduleName,
const char *file,
const unsigned int linenumber,
const char *function,
const char *format, ...)
348 fprintf(stderr,
"VuoLog() error: Invalid 'moduleName' argument (%p). You may need to rebuild the module calling VuoLog().\n", moduleName);
354 fprintf(stderr,
"VuoLog() error: Invalid 'file' argument (%p). You may need to rebuild the module calling VuoLog().\n", file);
360 fprintf(stderr,
"VuoLog() error: Invalid 'function' argument (%p). You may need to rebuild the module calling VuoLog().\n", function);
366 fprintf(stderr,
"VuoLog() error: Invalid 'format' argument (%p). You may need to rebuild the module calling VuoLog().\n", format);
373 va_start(args, format);
374 int size = vsnprintf(NULL, 0, format, args);
377 char *formattedString = (
char *)malloc(size+1);
378 va_start(args, format);
379 vsnprintf(formattedString, size+1, format, args);
382 char *formattedFunction = NULL;
386 if (function && function[0] ==
'_' && function[1] ==
'_')
388 int actualFunctionLength = atoi(function + 2);
389 if (actualFunctionLength)
390 formattedFunction = strndup(function + 3 + (
int)log10(actualFunctionLength), actualFunctionLength);
392 formattedFunction = strndup(function + 2, strrchr(function + 2,
'_') - (function + 2));
397 if (strncmp(formattedFunction,
"_ZN", 3) == 0)
400 int len, priorLen = 0;
401 while ((len = atoi(formattedFunction + pos)))
403 pos += 1 + (int)log10(len) + len;
406 char *f2 = strndup(formattedFunction + pos - priorLen, priorLen);
407 free(formattedFunction);
408 formattedFunction = f2;
413 const char *blockInvokePos = strstr(function,
"_block_invoke");
415 formattedFunction = strndup(function, blockInvokePos - function);
421 const char *f = formattedFunction ? formattedFunction : function;
422 size_t fLen = strlen(f);
423 if (f[fLen - 1] !=
']')
425 size_t mallocSize = fLen + 2 + 1;
426 char *f2 = (
char *)malloc(mallocSize);
427 strlcpy(f2, f, mallocSize);
428 strlcat(f2,
"()", mallocSize);
429 if (formattedFunction)
430 free(formattedFunction);
431 formattedFunction = f2;
435 const char *formattedFile = file;
438 formattedFile =
"(unknown)";
441 if (
const char *lastSlash = strrchr(formattedFile,
'/'))
442 formattedFile = lastSlash + 1;
447 static double priorTime = 0;
448 const char *separator =
"";
449 if (priorTime > 0 && time - priorTime > 0.5)
454 pthread_t thread = pthread_self();
455 char threadName[256];
457 strcpy(threadName,
"main");
460 bzero(threadName, 256);
461 int ret = pthread_getname_np(thread, threadName, 256);
462 if (!(ret == 0 && strlen(threadName)))
463 snprintf(threadName, 256,
"%llx", (uint64_t)thread);
467 const char *mainColor =
"\033[97m";
469 const char *metadataColor =
"\033[38;5;249m";
471 const char *separatorColor =
"\033[90m";
475 int pidColor = getpid() % 144 + 88;
479 : ((uint64_t)thread) % 144 + 88;
481 fprintf(stderr,
"%s%s[%s%8.3fs%s] %s%12.12s%s:%s%-12.12s %s[\033[38;5;%dm%5d%s:\033[38;5;%dm%-8.8s%s] %s%20.20s%s:%s%-4u %32.32s %s%s\033[0m\n",
491 moduleName ? moduleName :
"Vuo",
504 formattedFunction ? formattedFunction : function,
514 typedef void (*vuoMacOsLogInternalType)(
void *dso,
void *log, uint8_t type,
const char *message, ...);
515 typedef void (*vuoMacOsLogImplType)(
void *dso,
void *log, uint8_t type,
const char *format, uint8_t *buf, uint32_t size);
516 static vuoMacOsLogInternalType vuoMacOsLogInternal = NULL;
517 static vuoMacOsLogImplType vuoMacOsLogImpl = NULL;
518 static dispatch_once_t once = 0;
519 static bool debuggerAttached =
false;
520 dispatch_once(&once, ^{
523 if (operatingSystemVersion.majorVersion == 10 && operatingSystemVersion.minorVersion == 12)
525 vuoMacOsLogInternal = (vuoMacOsLogInternalType)dlsym(RTLD_SELF,
"_os_log_internal");
526 else if ((operatingSystemVersion.majorVersion == 10 && operatingSystemVersion.minorVersion > 12)
527 || operatingSystemVersion.majorVersion > 10)
529 vuoMacOsLogImpl = (vuoMacOsLogImplType)dlsym(RTLD_SELF,
"_os_log_impl");
532 if (!debuggerAttached)
534 void *log = os_log_create(
"org.vuo", formattedFile);
536 if (vuoMacOsLogInternal)
537 vuoMacOsLogInternal(&__dso_handle, log, 0 ,
"%{public}41s:%-4u %{public}s", formattedFunction ? formattedFunction : function, linenumber, formattedString);
538 else if (vuoMacOsLogImpl)
540 char *formattedForOsLog;
541 asprintf(&formattedForOsLog,
"%41s:%-4u %s", formattedFunction ? formattedFunction : function, linenumber, formattedString);
544 uint8_t logFormatDescriptor[12] = {
551 memcpy(logFormatDescriptor + 4, &formattedForOsLog, 8);
553 vuoMacOsLogImpl(&__dso_handle, log, 0 ,
"%{public}s", logFormatDescriptor,
sizeof(logFormatDescriptor));
555 free(formattedForOsLog);
563 static dispatch_once_t historyInitialized = 0;
564 dispatch_once(&historyInitialized, ^{
573 char *formattedPrefixedString;
574 asprintf(&formattedPrefixedString,
"t=%8.4fs %27.27s:%-4u %41.41s %s", time, formattedFile, linenumber, formattedFunction ? formattedFunction : function, formattedString);
575 free(formattedString);
576 if (formattedFunction)
577 free(formattedFunction);
599 if (VuoCrashReport.backtrace)
600 free(VuoCrashReport.backtrace);
608 char *message = (
char *)malloc(size);
613 strlcat(message,
"\n", size);
617 VuoCrashReport.backtrace = message;
683 size_t size = backtrace(array, 100);
684 char **strings = backtrace_symbols(array, size);
685 vector<string> outputStrings;
688 for (
size_t i = 1; i < size; i++)
691 const int lineNumberLen = 4;
692 string trimmedLine = strings[i] + lineNumberLen;
694 const int libraryLen = 36;
695 const int addressLen = 19;
696 string symbol = strings[i] + lineNumberLen + libraryLen + addressLen;
697 string instructionOffset = symbol.substr(symbol.find(
' '));
698 symbol = symbol.substr(0, symbol.find(
' '));
701 char *unmangled = abi::__cxa_demangle(symbol.c_str(),
nullptr,
nullptr, &status);
706 VuoLog_replaceString(unmangled,
"basic_string<char, char_traits<char>, allocator<char> >",
"string");
711 outputStrings.push_back(trimmedLine.substr(0, libraryLen + addressLen) + unmangled + instructionOffset);
715 outputStrings.push_back(trimmedLine);
722 auto last = outputStrings.back();
723 if (last.substr(0, 4) ==
"??? "
724 && last.find(
" 0x0 + ") != string::npos)
725 outputStrings.pop_back();
727 last = outputStrings.back();
728 if (last.substr(0, 13) ==
"libdyld.dylib"
729 && last.find(
" start + ") != string::npos)
730 outputStrings.pop_back();
733 remove_if(outputStrings.begin(), outputStrings.end(),
734 [](
const string &s) {
735 return s.find(
"_dispatch_queue_override_invoke") != string::npos
736 || s.find(
"_dispatch_root_queue_drain") != string::npos
737 || s.find(
"_dispatch_worker_thread2") != string::npos
738 || s.find(
"_dispatch_lane_serial_drain") != string::npos
739 || s.find(
"_dispatch_lane_barrier_sync_invoke_and_complete") != string::npos
740 || s.find(
"_dispatch_lane_invoke") != string::npos
741 || s.find(
"_dispatch_workloop_worker_thread") != string::npos
742 || s.find(
"_dispatch_continuation_pop") != string::npos
743 || s.find(
"_dispatch_main_queue_callback_4CF") != string::npos
744 || s.find(
"__CFRunLoopDoObservers") != string::npos
745 || s.find(
"__CFRunLoopDoSource0") != string::npos
746 || s.find(
"__CFRunLoopDoSources0") != string::npos
747 || s.find(
"__CFRunLoopRun") != string::npos
748 || s.find(
"__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__") != string::npos
749 || s.find(
"__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__") != string::npos
750 || s.find(
"__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__") != string::npos
751 || s.find(
"_CFXRegistrationPost") != string::npos
752 || s.find(
"_CFXNotification") != string::npos
753 || s.find(
"_NSWindowSendWindowDidMove") != string::npos
754 || s.find(
"_NSSendEventToObservers") != string::npos
755 || s.find(
"NSCarbonMenuImpl") != string::npos
756 || s.find(
"NSSLMMenuEventHandler") != string::npos
757 || s.find(
"CopyCarbonUIElementAttributeValue") != string::npos
758 || s.find(
"NSApplication(NSEvent) _") != string::npos
759 || s.find(
"NSApplication(NSAppleEventHandling) _") != string::npos
760 || s.find(
"withWindowOrderingObserverHeuristic") != string::npos
761 || s.find(
"aeProcessAppleEvent") != string::npos
762 || s.find(
"dispatchEventAndSendReply") != string::npos
763 || s.find(
"aeDispatchAppleEvent") != string::npos
764 || s.find(
"_NSAppleEventManagerGenericHandler") != string::npos
765 || s.find(
"NSWindow _") != string::npos
766 || s.find(
"HIServices") != string::npos
767 || s.find(
"HIToolbox") != string::npos
768 || s.find(
"RunCurrentEventLoopInMode") != string::npos
769 || s.find(
"ReceiveNextEventCommon") != string::npos
770 || s.find(
"_BlockUntilNextEventMatchingListInModeWithFilter") != string::npos
771 || s.find(
"_DPSNextEvent") != string::npos
772 || s.find(
"_pthread_wqthread") != string::npos
773 || s.find(
"qt_plugin_instance") != string::npos
774 || s.find(
"QWindowSystemInterface::") != string::npos
775 || s.find(
"QWidgetPrivate::") != string::npos
776 || s.find(
"QApplicationPrivate::") != string::npos
777 || s.find(
"QGuiApplicationPrivate::") != string::npos
778 || s.find(
"QCoreApplication::notifyInternal2") != string::npos
779 || s.find(
"QCoreApplicationPrivate::") != string::npos;
781 outputStrings.end());
785 return outputStrings;