Как перенаправить все ошибки, в том числе неотображаемые исключения, вызовы NSLog и другие журналы, в файл журнала в Mac OS X?

Я пытаюсь найти структуру ведения журнала для приложения Cocoa, написанного в ObjC.

Что я пытался сделать до сих пор:

  • Используйте NSLog, но затем понимайте, что его очень сложно настроить и перенаправить. Я полагаю, я мог взломать его и написать макрос, который получает информацию, которую я хочу, например, идентификатор потока, текущую функцию, текущую строку, текущий файл, текущее время, сообщение и т.д., А затем использует NSLog, однако...
  • NSLog в конечном счете использует NSLogv, который в конечном счете использует asl, поэтому я подумал "фантастически", я попробовал использовать asl вместо этого с клиентом и контекстом по умолчанию (если бы я делал это правильно, мне пришлось бы создать новый клиент для каждого потока), однако, если я не создаю макрос, это также очень многословно, и я заметил, что журналы, отправленные через asl, получили широковещательную широковещательную систему, тогда как NSLog только регистрировался в stderr, и я хочу, чтобы они оба переходили к одному и тому же войти!
  • Затем я заметил, что ошибки отформатированы по-другому (разные datestamp и т.д.), поэтому теперь есть третий контекст ведения журнала.

Какую настройку фреймворка lging можно использовать для того, чтобы ВСЕ сообщения регистрировались в этой структуре удобным образом, чтобы при возникновении проблемы с приложением разработчик мог получить файлы журнала и выяснить, что пошло не так?

Я не хочу просто перенаправлять stderr, я хочу иметь структурированный вывод журнала, содержащий все журналы. Я не хочу, чтобы некоторые журналы поступали на стандартный вывод, я не хочу, чтобы какие-либо журналы отправлялись в syslogd, я просто хочу, чтобы все журналы записывались в один файл, что надежно идентифицирует всю соответствующую информацию об этом сообщении журнала (например, идентификатор потока, сообщение, функция, называемая регистратором, и т.д.), в формате, который легко просматривать и визуализировать.

Я хочу перенаправить все текущие журналы в новый пункт назначения.

Есть ли у кого-нибудь предложения?

EDIT:

Фактически, то, что я хочу сделать, в терминах ObjC:

  • Сделайте "метод swizzling" в функции NSLog. Это возможно? Возможно ли (повторно) настроить использование системного регистратора Apple для переопределения любой предыдущей конфигурации службы в одном приложении?
  • Определите все места, где я должен поймать необработанные исключения. Это включает, но, возможно, не ограничивается: Необработанными Cocoa Исключениями. Необработанные исключения ObjC. Необработанные исключения С++. Сигналы Unix.
  • Поймать и зарегистрировать стек для ошибок, например, поднятых CoreGraphics. (Те, которые просто регистрируют сообщение "Добавить точку останова с помощью вашего отладчика!!!" ).

Ответы

Ответ 1

Вы можете перехватить сообщения NSLog() (но не ASL в целом) с помощью _NSSetLogCStringFunction(). Его документированный здесь для WebObjects 4 для Windows, но он существует и в текущих выпусках для Mac OS и iOS. Тем не менее, это частная функция, которая может исчезнуть в любое время, поэтому вы не должны полагаться на нее в выпущенном коде.

Если вы хотите быть в состоянии безопасно сделать это для не-отладочных сборников, я предлагаю дублировать этот запрос расширения на Радар.

Ответ 2

Вы можете использовать функцию Foundation NSSetUncaughtExceptionHandler, чтобы установить функцию обратного вызова, которая будет обрабатывать все неперехваченные исключения:

void CustomLogger(NSString *format, ...) {
   //do other awesome logging stuff here...
}

void uncaughtExceptionHandler(NSException *exception) {
   //do something useful, like this:
   CustomLogger(@"%@", [exception reason]);
}

NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);

Для NSLog вы можете использовать макрос, чтобы переопределить его:)

#define NSLog(...) CustomLogger(__VA_ARGS__);

Ответ 3

Вы можете перенаправить стандартный вывод ошибки в файл. Вот метод, который перенаправляет вывод консоли в файл в папке Documents Documents. Это может быть полезно, когда вы хотите протестировать свое приложение за пределами своей студии разработки, отключенной от вашего Mac.

-(void) redirectNSLogToDocuments {
 NSArray *allPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
 NSString *documentsDirectory = [allPaths objectAtIndex:0];
 NSString *pathForLog = [documentsDirectory stringByAppendingPathComponent:@"yourFile.txt"];
 freopen([pathForLog cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
}

После выполнения этого метода весь вывод, сгенерированный NSLog, будет перенаправлен в указанный файл. Чтобы открыть сохраненный файл, откройте "Органайзер", просмотрите файлы приложений и сохраните данные приложения где-нибудь в вашей файловой системе, а не просто перейдите в папку "Документы".