To ciekawy Żądamy, ale jest to wykonalne, jeśli chcesz zaakceptować trochę kosztów związanych z wywołaniem funkcji dla każdego dziennika, który zostanie pominięty. Wewnątrz EtPanKit framework znajduje się niezła funkcja, która sprawdza, czy pliki, które próbują wywoływać funkcję rejestru, pasują do tablicy zdefiniowanych klas w pliku . Oprócz tego, że jest doskonałym filtrem do debugowania, wystarczy zwolnić wszystkie klucze z pliku plist lub określić inny w wersji Release bez żadnych wartości związanych z kluczem LEPLogEnabledFilenames
.
W interesie zapobiegania link-rot, oto sama funkcja i związane z makr, które sprawiają, że nieco ładniejsza zadzwonić:
#define LEPLogStack(...) LEPLogInternal(__FILE__, __LINE__, 1, __VA_ARGS__)
#define LEPLog(...) LEPLogInternal(__FILE__, __LINE__, 0, __VA_ARGS__)
#import <Foundation/Foundation.h>
#import <libgen.h>
#import <time.h>
#import <sys/time.h>
#include <execinfo.h>
#include <pthread.h>
static NSSet * enabledFilesSet = nil;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void LEPLogInternal(const char * filename, unsigned int line, int dumpStack, NSString * format, ...)
{
va_list argp;
NSString * str;
NSAutoreleasePool * pool;
char * filenameCopy;
char * lastPathComponent;
struct timeval tv;
struct tm tm_value;
//NSDictionary * enabledFilenames;
pool = [[NSAutoreleasePool alloc] init];
pthread_mutex_lock(&lock);
if (enabledFilesSet == nil) {
enabledFilesSet = [[NSSet alloc] initWithArray:[[NSUserDefaults standardUserDefaults] arrayForKey:LEPLogEnabledFilenames]];
}
pthread_mutex_unlock(&lock);
NSString * fn;
fn = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:filename length:strlen(filename)];
fn = [fn lastPathComponent];
if (![enabledFilesSet containsObject:fn]) {
[pool release];
return;
}
va_start(argp, format);
str = [[NSString alloc] initWithFormat:format arguments:argp];
va_end(argp);
NSString * outputFileName = [[NSUserDefaults standardUserDefaults] stringForKey:LEPLogOutputFilename];
static FILE * outputfileStream = NULL;
if ((NULL == outputfileStream) && outputFileName)
{
outputfileStream = fopen([outputFileName UTF8String], "w+");
}
if (NULL == outputfileStream)
outputfileStream = stderr;
gettimeofday(&tv, NULL);
localtime_r(&tv.tv_sec, &tm_value);
fprintf(outputfileStream, "%04u-%02u-%02u %02u:%02u:%02u.%03u ", tm_value.tm_year + 1900, tm_value.tm_mon + 1, tm_value.tm_mday, tm_value.tm_hour, tm_value.tm_min, tm_value.tm_sec, tv.tv_usec/1000);
//fprintf(stderr, "%10s ", [[[NSDate date] description] UTF8String]);
fprintf(outputfileStream, "[%s:%u] ", [[[NSProcessInfo processInfo] processName] UTF8String], [[NSProcessInfo processInfo] processIdentifier]);
filenameCopy = strdup(filename);
lastPathComponent = basename(filenameCopy);
fprintf(outputfileStream, "(%s:%u) ", lastPathComponent, line);
free(filenameCopy);
fprintf(outputfileStream, "%s\n", [str UTF8String]);
[str release];
if (dumpStack) {
void * frame[128];
int frameCount;
int i;
frameCount = backtrace(frame, 128);
for(i = 0 ; i < frameCount ; i ++) {
fprintf(outputfileStream, " %p\n", frame[i]);
}
}
if (outputFileName)
{
fflush(outputfileStream);
}
[pool release];
}
Więc niech mi to wprost: Chcesz czasie kompilacji zróżnicowanie ścieżek kod bez żadnych narzędzi, które mamy używane do różnicowania w czasie kompilacji od późnych lat 80-tych? Makra preprocesora nie są niebezpiecznymi zależnościami, to jedyny sposób, w jaki będzie to działało bez żadnych kosztów ogólnych. Jeśli martwisz się, że makra zostały zmienione, dlaczego nie "# błędu", gdy są '# ifndef''d. – CodaFi
@CodaFi dla mnie makra preprocesora są idealnie w porządku. Po prostu nie nazywam strzałów, więc muszę podać alternatywę. :) I nie jest to "różnicowanie w czasie kompilacji", wystarczy wyłączyć wyjście. – Peres
Dobra, myślę, że mam rozwiązanie. – CodaFi