From: znek Date: Fri, 19 Nov 2004 04:37:51 +0000 (+0000) Subject: stabilized NGLogging - adapted enhancements in parts of NGObjWeb X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3cf45da9d268dc3f8334a6858bc57736916dae19;p=sope stabilized NGLogging - adapted enhancements in parts of NGObjWeb git-svn-id: http://svn.opengroupware.org/SOPE/trunk@401 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- diff --git a/sope-appserver/NGObjWeb/ChangeLog b/sope-appserver/NGObjWeb/ChangeLog index 2b5fad2f..97c6b243 100644 --- a/sope-appserver/NGObjWeb/ChangeLog +++ b/sope-appserver/NGObjWeb/ChangeLog @@ -1,3 +1,19 @@ +2004-11-19 Marcus Mueller + + * v4.5.95 + + * Defaults.plist: new defaults for NGLogging + + * WOHttpAdaptor/WOHttpAdaptor.m: rewrote transaction logging to use + NGLogging. Configuration for transActionLogger is stored in + Defaults.plist. + NOTE: no profiling has been done, yet - thus the profiling + information needs to be updated (a TODO has been placed at the + appropriate place). + + * DynamicElements/_WOTemporaryHyperlink.m: added correct cast to + circumvent gcc bug (false warning). + 2004-11-19 Helge Hess * v4.5.94 diff --git a/sope-appserver/NGObjWeb/Defaults.plist b/sope-appserver/NGObjWeb/Defaults.plist index 14892079..e1ca29a2 100644 --- a/sope-appserver/NGObjWeb/Defaults.plist +++ b/sope-appserver/NGObjWeb/Defaults.plist @@ -1,8 +1,11 @@ { - NGObjWeb_doc_ = "NSUserDefaults for NGObjWeb"; + NGObjWeb_doc_ = "NSUserDefaults for NGObjWeb"; + NGLogDefaultAppenderClass = "NGLogStdoutAppender"; + NGLogDefaultLogLevel = "INFO"; + NGLogDefaultLogEventFormatterClass = "NGLogEventDetailedFormatter"; WOAdaptor = "WOHttpAdaptor"; - WOAdaptorLogPath = ""; + WOAdaptorLogPath = ""; WOAdditionalAdaptors = ( ); WOApplicationBaseURL = "/WebObjects"; WOApplicationSuffix = ".woa"; @@ -17,12 +20,12 @@ WOCoreOnApplicationException = NO; WOCoreOnAwakeComponentInCtxDealloc = NO; WOCoreOnHTTPAdaptorException = NO; - WOCoreOnRecursiveSubcomponents = NO; + WOCoreOnRecursiveSubcomponents = NO; WOCoreOnXmlRpcFault = NO; WODebugActions = NO; - WODebugComponentAwake = NO; + WODebugComponentAwake = NO; WODebugComponentDefinition = NO; - WODebugComponentLookup = NO; + WODebugComponentLookup = NO; WODebugCursor = NO; WODebugHttpTransaction = NO; WODebugKeyPathAssociation = NO; @@ -56,6 +59,17 @@ WOHttpAdaptor_LogStream = NO; WOHttpAllowHost = "localhost"; WOHttpTransactionUseSimpleParser = NO; + WOHttpTransactionLoggerConfig = { + "LogLevel" = "INFO"; + "Appenders" = ( + { + "Class" = "NGLogStdoutAppender"; + "Formatter" = { + "Class" = "NGLogEventFormatter"; + }; + }, + ); + }; WOIncludeCommentsInResponse = YES; WOIsRedirectionEnabled = NO; WOKeyPathAssociationsCacheSize = 200; @@ -96,13 +110,13 @@ WOSimpleHTTPParserMaxUploadSizeInKB = 262144; WOStatsStylesheetName = "WOStats.xsl"; WOUseRelativeURLs = YES; - WOUseGlobalCookiePath = YES; + WOUseGlobalCookiePath = YES; WOValueAssociationsCacheSize = 200; WOWorkerThreadCount = 0; WOxFileExtensions = ( wox, xtmpl, xhtml ); WOxElemBuilder_LogAssociationMapping = NO; WOxElemBuilder_LogAssociationCreation = NO; - WOxComponentElemBuilderDebugEnabled = NO; + WOxComponentElemBuilderDebugEnabled = NO; WOxLogBuilderQueue = NO; WOxBuilderClasses = ( WOxControlElemBuilder, diff --git a/sope-appserver/NGObjWeb/DynamicElements/_WOTemporaryHyperlink.m b/sope-appserver/NGObjWeb/DynamicElements/_WOTemporaryHyperlink.m index deeb0153..42c5537b 100644 --- a/sope-appserver/NGObjWeb/DynamicElements/_WOTemporaryHyperlink.m +++ b/sope-appserver/NGObjWeb/DynamicElements/_WOTemporaryHyperlink.m @@ -63,7 +63,8 @@ static Class _WODirectActionHyperlinkClass = Nil; WOHyperlinkInfo *info; Class linkClass = Nil; - if ((info = [[WOHyperlinkInfo alloc] initWithConfig:(id)_config]) == nil) { + if ((info = [(WOHyperlinkInfo *)[WOHyperlinkInfo alloc] + initWithConfig:(id)_config]) == nil) { return nil; } diff --git a/sope-appserver/NGObjWeb/NGHttp/NGHttp.xcode/project.pbxproj b/sope-appserver/NGObjWeb/NGHttp/NGHttp.xcode/project.pbxproj index 9e6541d1..ad448488 100644 --- a/sope-appserver/NGObjWeb/NGHttp/NGHttp.xcode/project.pbxproj +++ b/sope-appserver/NGObjWeb/NGHttp/NGHttp.xcode/project.pbxproj @@ -464,7 +464,7 @@ ); buildSettings = { DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 4.5.91; + DYLIB_CURRENT_VERSION = 4.5.95; FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks"; FRAMEWORK_VERSION = A; GCC_PRECOMPILE_PREFIX_HEADER = YES; diff --git a/sope-appserver/NGObjWeb/NGObjWeb.xcode/project.pbxproj b/sope-appserver/NGObjWeb/NGObjWeb.xcode/project.pbxproj index 0e89de1b..4de323b5 100644 --- a/sope-appserver/NGObjWeb/NGObjWeb.xcode/project.pbxproj +++ b/sope-appserver/NGObjWeb/NGObjWeb.xcode/project.pbxproj @@ -1655,7 +1655,7 @@ ); buildSettings = { DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 4.5.91; + DYLIB_CURRENT_VERSION = 4.5.95; FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks"; FRAMEWORK_VERSION = A; GCC_PRECOMPILE_PREFIX_HEADER = YES; diff --git a/sope-appserver/NGObjWeb/SoObjects/SoObjects.xcode/project.pbxproj b/sope-appserver/NGObjWeb/SoObjects/SoObjects.xcode/project.pbxproj index 35cf8112..be98e782 100644 --- a/sope-appserver/NGObjWeb/SoObjects/SoObjects.xcode/project.pbxproj +++ b/sope-appserver/NGObjWeb/SoObjects/SoObjects.xcode/project.pbxproj @@ -289,7 +289,7 @@ ); buildSettings = { DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 4.5.91; + DYLIB_CURRENT_VERSION = 4.5.95; FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks"; FRAMEWORK_VERSION = A; GCC_PRECOMPILE_PREFIX_HEADER = NO; diff --git a/sope-appserver/NGObjWeb/Version b/sope-appserver/NGObjWeb/Version index 625a9567..cfdbb476 100644 --- a/sope-appserver/NGObjWeb/Version +++ b/sope-appserver/NGObjWeb/Version @@ -1,6 +1,6 @@ # version file -SUBMINOR_VERSION:=94 +SUBMINOR_VERSION:=95 # v4.5.91 requires libNGExtensions v4.5.134 # v4.5.84 requires libNGExtensions v4.5.127 diff --git a/sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m b/sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m index d4c35dba..2a2d62b6 100644 --- a/sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m +++ b/sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m @@ -58,9 +58,10 @@ NSString *WOAsyncResponse = @"WOAsyncResponse"; static NSMutableDictionary *pendingTransactions = nil; // THREAD static BOOL useSimpleParser = YES; static int doCore = -1; -static NSString *adLogPath = nil; -static NGLogger *debugLogger = nil; -static NGLogger *perfLogger = nil; +static NSString *adLogPath = nil; +static NGLogger *debugLogger = nil; +static NGLogger *perfLogger = nil; +static NGLogger *transActionLogger = nil; + (int)version { return 2; @@ -73,9 +74,10 @@ static NGLogger *perfLogger = nil; if (didInit) return; didInit = YES; - lm = [NGLoggerManager defaultLoggerManager]; - perfLogger = [lm loggerForDefaultKey:@"WOProfileHttpAdaptor"]; - debugLogger = [lm loggerForDefaultKey:@"WODebugHttpTransaction"]; + lm = [NGLoggerManager defaultLoggerManager]; + perfLogger = [lm loggerForDefaultKey:@"WOProfileHttpAdaptor"]; + debugLogger = [lm loggerForDefaultKey:@"WODebugHttpTransaction"]; + transActionLogger = [lm loggerForClass:self]; ud = [NSUserDefaults standardUserDefaults]; useSimpleParser = [ud boolForKey:@"WOHttpTransactionUseSimpleParser"]; @@ -869,15 +871,18 @@ static __inline__ const unsigned char *monthAbbr(int m) { connection:(id)_connection { /* + NOTE: *obsoleted profiling information* + TODO: update profiling info! (left the old one for comparison) Profiling: this method takes 0.95% of -run if the output is piped to /dev/null on OSX, morphing caldate to string is 0.79% of that. */ - NSString *remoteHost = @"-"; - NSNumber *zippedLen; - NSCalendarDate *now; - NSDate *lstartDate; - NSDictionary *startStats; - + NSString *remoteHost; + NSNumber *zippedLen; + NSCalendarDate *now; + NSDate *lstartDate; + NSDictionary *startStats; + NSMutableString *buf; + lstartDate = [_request startDate]; startStats = [_request startStatistics]; zippedLen = [[_response userInfo] objectForKey:@"WOResponseZippedLength"]; @@ -902,27 +907,34 @@ static __inline__ const unsigned char *monthAbbr(int m) { // this is supposed to be in GMT ! TODO: explicitly set GMT now = [NSCalendarDate calendarDate]; - - /* print standard info */ - printf("%s - - [%02i/%s/%04i:%02i:%02i:%02i GMT] \"%s %s %s\" %i %i", - remoteHost ? [remoteHost cString] : "-", - [now dayOfMonth], - monthAbbr([now monthOfYear]), - [now yearOfCommonEra], - [now hourOfDay], [now minuteOfHour], [now secondOfMinute], - [[_request method] cString], - [[_request uri] cString], - [[_request httpVersion] cString], - [_response status], - [[_response content] length]); - - /* print duration */ + + buf = [[NSMutableString alloc] initWithCapacity:160]; /* 2 terminal lines */ + + /* append standard info */ + [buf appendString:remoteHost]; + [buf appendString:@" - - ["]; + [buf appendFormat:@"%02i/%s/%04i:%02i:%02i:%02i", + [now dayOfMonth], + monthAbbr([now monthOfYear]), + [now yearOfCommonEra], + [now hourOfDay], [now minuteOfHour], [now secondOfMinute]]; + [buf appendString:@" GMT] \""]; + [buf appendString:[_request method]]; + [buf appendString:@" "]; + [buf appendString:[_request uri]]; + [buf appendString:@" "]; + [buf appendString:[_request httpVersion]]; + [buf appendString:@"\" "]; + [buf appendFormat:@"%i", [_response status]]; + [buf appendFormat:@" %i", [[_response content] length]]; + + /* append duration */ if (lstartDate) - printf(" %.3f", [now timeIntervalSinceDate:lstartDate]); + [buf appendFormat:@" %.3f", [now timeIntervalSinceDate:lstartDate]]; else - printf(" -"); + [buf appendString:@" -"]; - /* print zip level */ + /* append zip level */ if (zippedLen) { double p; double unzippedLen; @@ -930,25 +942,24 @@ static __inline__ const unsigned char *monthAbbr(int m) { unzippedLen = [[[_response userInfo] objectForKey:@"WOResponseUnzippedLength"] unsignedIntValue]; - - printf(" %d", (unsigned int)unzippedLen); + [buf appendFormat:@" %d", (unsigned int)unzippedLen]; if ([zippedLen unsignedIntValue] == unzippedLen) { - printf(" -"); + [buf appendString:@" -"]; } else { p = unzippedLen / 100.0; // one percent p = [zippedLen doubleValue] / p; p = 100.0 - p; - printf(" %-2d%%", (unsigned int)p); + [buf appendFormat:@" %-2d%%", (unsigned int)p]; } } else { /* content was not zipped */ - printf(" - -"); + [buf appendString:@" - -"]; } - /* print statistics */ + /* append statistics */ if (startStats) { static NSProcessInfo *pi = nil; @@ -965,21 +976,20 @@ static __inline__ const unsigned char *monthAbbr(int m) { diff *= 4; /* in KB */ if (diff == 0) - printf(" 0"); + [buf appendString:@" 0"]; else if (diff > 999) - printf(" %iM", diff / 1024); + [buf appendFormat:@" %iM", diff / 1024]; else - printf(" %iK", diff); + [buf appendFormat:@" %iK", diff]; } else - printf(" ?"); + [buf appendString:@" ?"]; } else - printf(" -"); - - /* flush log */ - puts(""); - fflush(stdout); + [buf appendString:@" -"]; + + [transActionLogger logLevel:NGLogLevelInfo message:buf]; + [buf release]; } /* NGHttpMessageParserDelegate */ diff --git a/sope-appserver/NGObjWeb/WebDAV/WebDAV.xcode/project.pbxproj b/sope-appserver/NGObjWeb/WebDAV/WebDAV.xcode/project.pbxproj index ef181380..8d0b2bd4 100644 --- a/sope-appserver/NGObjWeb/WebDAV/WebDAV.xcode/project.pbxproj +++ b/sope-appserver/NGObjWeb/WebDAV/WebDAV.xcode/project.pbxproj @@ -229,7 +229,7 @@ ); buildSettings = { DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 4.5.91; + DYLIB_CURRENT_VERSION = 4.5.95; FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks"; FRAMEWORK_VERSION = A; GCC_PRECOMPILE_PREFIX_HEADER = NO; diff --git a/sope-core/NGExtensions/ChangeLog b/sope-core/NGExtensions/ChangeLog index 79692e2a..bc47f01f 100644 --- a/sope-core/NGExtensions/ChangeLog +++ b/sope-core/NGExtensions/ChangeLog @@ -1,3 +1,8 @@ +2004-11-19 Marcus Mueller + + * NGLogging: updated - API considered stable now. + NOTE: "make distclean" is required this time. (v4.5.136) + 2004-11-19 Helge Hess * v4.5.135 diff --git a/sope-core/NGExtensions/GNUmakefile b/sope-core/NGExtensions/GNUmakefile index 18d41da5..19f1e3d8 100644 --- a/sope-core/NGExtensions/GNUmakefile +++ b/sope-core/NGExtensions/GNUmakefile @@ -126,8 +126,9 @@ NGLogging_HEADER_FILES = \ NGLogger.h \ NGLoggerManager.h \ NGLogEvent.h \ + NGLogEventFormatter.h \ NGLogAppender.h \ - NGLogConsoleAppender.h \ + NGLogFileHandleAppender.h \ NGLogSyslogAppender.h \ diff --git a/sope-core/NGExtensions/NGExtensions.xcode/project.pbxproj b/sope-core/NGExtensions/NGExtensions.xcode/project.pbxproj index 9f873304..26862351 100644 --- a/sope-core/NGExtensions/NGExtensions.xcode/project.pbxproj +++ b/sope-core/NGExtensions/NGExtensions.xcode/project.pbxproj @@ -87,6 +87,109 @@ COMPILER_FLAGS = "-I.."; }; }; + AD8B5D95074CF58C001AF5D3 = { + fileEncoding = 5; + indentWidth = 2; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGLogFileHandleAppender.m; + refType = 4; + sourceTree = ""; + }; + AD8B5D97074CF58C001AF5D3 = { + fileRef = AD8B5D95074CF58C001AF5D3; + isa = PBXBuildFile; + settings = { + }; + }; + AD8B5D98074CF614001AF5D3 = { + fileEncoding = 5; + indentWidth = 2; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGLogStdoutAppender.m; + refType = 4; + sourceTree = ""; + }; + AD8B5D99074CF614001AF5D3 = { + fileRef = AD8B5D98074CF614001AF5D3; + isa = PBXBuildFile; + settings = { + }; + }; + AD8B5DDC074CF7C8001AF5D3 = { + fileEncoding = 5; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGLogFileHandleAppender.h; + refType = 4; + sourceTree = ""; + }; + AD8B5DDD074CF7C8001AF5D3 = { + fileRef = AD8B5DDC074CF7C8001AF5D3; + isa = PBXBuildFile; + settings = { + ATTRIBUTES = ( + Public, + ); + }; + }; + AD8B5F6C074D46D0001AF5D3 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGLogEventFormatter.m; + refType = 4; + sourceTree = ""; + }; + AD8B5F6D074D46D0001AF5D3 = { + fileRef = AD8B5F6C074D46D0001AF5D3; + isa = PBXBuildFile; + settings = { + }; + }; + AD8B5FBE074D4D18001AF5D3 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGLogEventFormatter.h; + refType = 4; + sourceTree = ""; + }; + AD8B5FBF074D4D18001AF5D3 = { + fileRef = AD8B5FBE074D4D18001AF5D3; + isa = PBXBuildFile; + settings = { + }; + }; + AD8B5FFB074D57B2001AF5D3 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGLogEventDetailedFormatter.m; + refType = 4; + sourceTree = ""; + }; + AD8B5FFC074D57B2001AF5D3 = { + fileRef = AD8B5FFB074D57B2001AF5D3; + isa = PBXBuildFile; + settings = { + }; + }; + AD8B6017074D59B4001AF5D3 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGLogStderrAppender.m; + refType = 4; + sourceTree = ""; + }; + AD8B6018074D59B4001AF5D3 = { + fileRef = AD8B6017074D59B4001AF5D3; + isa = PBXBuildFile; + settings = { + }; + }; ADCD51360743BBBC0071C1A1 = { children = ( AD595AB00745170400B2C064, @@ -138,24 +241,6 @@ refType = 4; sourceTree = ""; }; - ADCD513B0743BBE10071C1A1 = { - fileEncoding = 5; - indentWidth = 2; - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - path = NGLogConsoleAppender.h; - refType = 4; - sourceTree = ""; - }; - ADCD513C0743BBE10071C1A1 = { - fileEncoding = 5; - indentWidth = 2; - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.objc; - path = NGLogConsoleAppender.m; - refType = 4; - sourceTree = ""; - }; ADCD513D0743BBE10071C1A1 = { fileEncoding = 5; indentWidth = 2; @@ -243,21 +328,6 @@ settings = { }; }; - ADCD514A0743BBE10071C1A1 = { - fileRef = ADCD513B0743BBE10071C1A1; - isa = PBXBuildFile; - settings = { - ATTRIBUTES = ( - Public, - ); - }; - }; - ADCD514B0743BBE10071C1A1 = { - fileRef = ADCD513C0743BBE10071C1A1; - isa = PBXBuildFile; - settings = { - }; - }; ADCD514C0743BBE10071C1A1 = { fileRef = ADCD513D0743BBE10071C1A1; isa = PBXBuildFile; @@ -337,8 +407,9 @@ ADCD513F0743BBE10071C1A1, ADCD52020743D8CA0071C1A1, ADCD513D0743BBE10071C1A1, + AD8B5FBE074D4D18001AF5D3, ADCD51390743BBE10071C1A1, - ADCD513B0743BBE10071C1A1, + AD8B5DDC074CF7C8001AF5D3, ADCD51420743BBE10071C1A1, ); fileEncoding = 5; @@ -354,10 +425,16 @@ ADCD51400743BBE10071C1A1, ADCD52030743D8CA0071C1A1, ADCD513E0743BBE10071C1A1, + AD8B5F6C074D46D0001AF5D3, + AD8B5FFB074D57B2001AF5D3, ADCD513A0743BBE10071C1A1, - ADCD513C0743BBE10071C1A1, ADCD51430743BBE10071C1A1, + AD8B5D95074CF58C001AF5D3, + AD8B5D98074CF614001AF5D3, + AD8B6017074D59B4001AF5D3, ); + fileEncoding = 5; + indentWidth = 2; isa = PBXGroup; name = Classes; refType = 4; @@ -1502,13 +1579,14 @@ ADD45B6006FEF017004BBD65, AD4BF6D60703147A006FB665, ADCD51480743BBE10071C1A1, - ADCD514A0743BBE10071C1A1, ADCD514C0743BBE10071C1A1, ADCD514E0743BBE10071C1A1, ADCD51500743BBE10071C1A1, ADCD51510743BBE10071C1A1, ADCD51530743BBE10071C1A1, ADCD52040743D8CA0071C1A1, + AD8B5DDD074CF7C8001AF5D3, + AD8B5FBF074D4D18001AF5D3, ); isa = PBXHeadersBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -1600,11 +1678,15 @@ AD4BF6EC070314EE006FB665, AD665E3A071F00AF00EC5911, ADCD51490743BBE10071C1A1, - ADCD514B0743BBE10071C1A1, ADCD514D0743BBE10071C1A1, ADCD514F0743BBE10071C1A1, ADCD51520743BBE10071C1A1, ADCD52050743D8CA0071C1A1, + AD8B5D97074CF58C001AF5D3, + AD8B5D99074CF614001AF5D3, + AD8B5F6D074D46D0001AF5D3, + AD8B5FFC074D57B2001AF5D3, + AD8B6018074D59B4001AF5D3, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -1633,7 +1715,7 @@ ); buildSettings = { DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 4.5.134; + DYLIB_CURRENT_VERSION = 4.5.136; FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks"; FRAMEWORK_VERSION = A; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -1747,6 +1829,8 @@ ADD65D8E06DA3830007161CA, ADD65D8F06DA3830007161CA, ); + fileEncoding = 5; + indentWidth = 2; isa = PBXGroup; name = Headers; path = NGExtensions; diff --git a/sope-core/NGExtensions/NGExtensions/NGLogAppender.h b/sope-core/NGExtensions/NGExtensions/NGLogAppender.h index 6117a3fc..f8b805fe 100644 --- a/sope-core/NGExtensions/NGExtensions/NGLogAppender.h +++ b/sope-core/NGExtensions/NGExtensions/NGLogAppender.h @@ -26,23 +26,50 @@ NGLogAppender Abstract superclass for all log appenders. + + NGLogAppender honours the following user default keys: + + User Default key Function + ---------------------------------------------------------------------------- + NGLogDefaultAppenderClass The appender class to use if no class + information was provided by the configuration. + The fallback is "NGLogStdoutAppender". + + + The following keys in the configuration dictionary will be recognized: + + Key Function + ---------------------------------------------------------------------------- + "Class" The class to use for instance creation. If no + class name is provided, the fallback path + described above will be taken. + + "Formatter" Dictionary suitable as configuration + provided to NGLogEventFormatters's factory + method. Please see NGLogEventFormatteer.h for + further explanation. */ #import #include -@class NGLogEvent; +@class NSDictionary, NGLogEvent, NGLogEventFormatter; @interface NGLogAppender : NSObject { + NGLogEventFormatter *formatter; } +/* factory method */ ++ (id)logAppenderFromConfig:(NSDictionary *)_config; + +/* designated initializer */ +- (id)initWithConfig:(NSDictionary *)_config; + /* subclass responsibility */ - (void)appendLogEvent:(NGLogEvent *)_event; - (NSString *)formattedEvent:(NGLogEvent *)_event; -- (NSString *)localizedNameOfLogLevel:(NGLogLevel)_level; - @end #endif /* __NGExtensions_NGLogAppender_H_ */ diff --git a/sope-core/NGExtensions/NGExtensions/NGLogEvent.h b/sope-core/NGExtensions/NGExtensions/NGLogEvent.h index 4277eff0..f46d5ec7 100644 --- a/sope-core/NGExtensions/NGExtensions/NGLogEvent.h +++ b/sope-core/NGExtensions/NGExtensions/NGLogEvent.h @@ -34,7 +34,7 @@ #import #include -@class NSString; +@class NSString, NSCalendarDate; @interface NGLogEvent : NSObject { @@ -49,7 +49,7 @@ - (NGLogLevel)level; - (NSString *)message; -- (NSDate *)date; +- (NSCalendarDate *)date; @end diff --git a/sope-core/NGExtensions/NGExtensions/NGLogEventFormatter.h b/sope-core/NGExtensions/NGExtensions/NGLogEventFormatter.h new file mode 100644 index 00000000..c8fab922 --- /dev/null +++ b/sope-core/NGExtensions/NGExtensions/NGLogEventFormatter.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2004 SKYRIX Software AG + + This file is part of OpenGroupware.org. + + OGo is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + OGo is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with OGo; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +#ifndef __NGExtensions_NGLogEventFormatter_H_ +#define __NGExtensions_NGLogEventFormatter_H_ + +/* + NGLogEventFormatter + + Suits as factory and base class for all custom log event formatters. + Its purpose is to offer a lightweight interface to transform NGLogEvent + objects into string representations. + + + NGLogEventFormatter honours the following user default keys: + + User Default key Function + ---------------------------------------------------------------------------- + NGLogDefaultLogEventFormatterClass The formatter class to use if no class + information was provided by the + configuration. + The fallback is "NGLogEventFormatter". + + The following keys in the configuration dictionary will be recognized: + + Key Function + ---------------------------------------------------------------------------- + "Class" The class to use for instance creation. If no + class name is provided, the fallback path + described above will be taken. +*/ + +#import +#include + +@class NSDictionary, NGLogEvent; + +@interface NGLogEventFormatter : NSObject +{ +} + ++ (id)logEventFormatterFromConfig:(NSDictionary *)_config; + +- (id)initWithConfig:(NSDictionary *)_config; + +/* formatting */ +- (NSString *)formattedEvent:(NGLogEvent *)_event; + +@end + +#endif /* __NGExtensions_NGLogEventFormatter_H_ */ diff --git a/sope-core/NGExtensions/NGExtensions/NGLogFileHandleAppender.h b/sope-core/NGExtensions/NGExtensions/NGLogFileHandleAppender.h new file mode 100644 index 00000000..0505ead9 --- /dev/null +++ b/sope-core/NGExtensions/NGExtensions/NGLogFileHandleAppender.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2004 SKYRIX Software AG + + This file is part of OpenGroupware.org. + + OGo is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + OGo is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with OGo; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#ifndef __NGExtensions_NGLogFileHandleAppender_H_ +#define __NGExtensions_NGLogFileHandleAppender_H_ + +/* + NGLogFileHandleAppender + + Suits as an abstract base class for all NSFileHandle based appenders. + */ + +#include +#import /* for NSStringEncoding */ + +@class NSFileHandle, NSDictionary; + +@interface NGLogFileHandleAppender : NGLogAppender +{ + NSFileHandle *fh; + NSStringEncoding encoding; + BOOL flushImmediately; +} + +- (BOOL)isFileHandleOpen; +- (void)openFileHandleWithConfig:(NSDictionary *)_config; +- (void)closeFileHandle; + +@end + +#endif /* __NGExtensions_NGLogFileHandleAppender_H_ */ diff --git a/sope-core/NGExtensions/NGExtensions/NGLogger.h b/sope-core/NGExtensions/NGExtensions/NGLogger.h index 9ddb2de6..cf18eec0 100644 --- a/sope-core/NGExtensions/NGExtensions/NGLogger.h +++ b/sope-core/NGExtensions/NGExtensions/NGLogger.h @@ -29,26 +29,66 @@ only if this minimum log level is satisfied - otherwise it silently drops these messages. - Note: Except in rare circumstances, do not allocate loggers yourself. Always - try to use the appropriate API of NGLoggerManager if possible. + NGLogger also offers a factory to instantiate loggers from configs stored + in NSUserDefaults. + + NOTE: Except in rare circumstances, do not allocate loggers yourself! + Always try to use the appropriate API of NGLoggerManager if possible. + + + NGLogger honours the following user default keys: + + User Default key Function + ---------------------------------------------------------------------------- + NGLogDefaultLogLevel The log level to use as a fallback, if no + log level is provided during initialization. + The default is "INFO". + + + The following keys in the configuration dictionary will be recognized: + + Key Function + ---------------------------------------------------------------------------- + "LogLevel" The log level to use for this logger. If no + log level is provided, sets log level according + to fallback described above. + + "Appenders" Array of dictionaries suitable as configuration + provided to NGLogAppender's factory method. + Please see NGLogAppender.h for further + explanation. + + LoggerConfig example: + + WOHttpTransactionLoggerConfig = { + "LogLevel" = "INFO"; + "Appenders" = ( + { + "Class" = "NGLogStdoutAppender"; + "Formatter" = { + "Class" = "NGLogEventFormatter"; + }; + }, + ); + }; - Note: Currently the NGLogger implementation lacks an API for configuring - appenders. Until this has been done appropriately, use the - "NGLogDefaultAppenderClass" user default to select an appropriate - default appender. If this default isn't set, "NGLogConsoleAppender" - is used. */ #import #include +@class NSMutableArray, NSString, NSDictionary, NGLogAppender; + @interface NGLogger : NSObject { - NGLogLevel logLevel; - id _appender; // going away as soon as we have a config + NSMutableArray *appenders; + @public + NGLogLevel logLevel; } -+ (id)defaultLogger; ++ (id)loggerWithConfigFromUserDefaults:(NSString *)_defaultName; + +- (id)initWithConfig:(NSDictionary *)_config; - (id)initWithLogLevel:(NGLogLevel)_level; /* accessors */ @@ -56,10 +96,12 @@ - (void)setLogLevel:(NGLogLevel)_level; - (NGLogLevel)logLevel; +- (void)addAppender:(NGLogAppender *)_appender; +- (void)removeAppender:(NGLogAppender *)_appender; - /* logging */ +- (void)logLevel:(NGLogLevel)_level message:(NSString *)_msg; /* conditions */ diff --git a/sope-core/NGExtensions/NGExtensions/NGLoggerManager.h b/sope-core/NGExtensions/NGExtensions/NGLoggerManager.h index 34e65f88..b78b6de2 100644 --- a/sope-core/NGExtensions/NGExtensions/NGLoggerManager.h +++ b/sope-core/NGExtensions/NGExtensions/NGLoggerManager.h @@ -30,9 +30,20 @@ same name/key. Also, NGLoggerManager offers conditional creation of loggers based on user default keys (and special values associated with these keys). - It's planned that NGLoggerManager will be provided with a configuration of - some sort at a later stage, so configuration of log levels and appenders for - loggers can reach a similar dynamism as is currently achieved in Log4J. + NGLoggerManager honours the following user default keys: + + User Default key Function + ---------------------------------------------------------------------------- + LoggerConfig contains the configuration of the logger + named . Depending on what method you used + to retrieve the logger, is either + the user default key, class name or another + arbitrary name. The config found for that key + is used to initialize the logger instance. + + NGLogDebugAllEnabled if set to "YES" will always return a logger + when -loggerForDefaultKey: is called. + */ #import diff --git a/sope-core/NGExtensions/NGExtensions/NGLogging.h b/sope-core/NGExtensions/NGExtensions/NGLogging.h index 0cd278b3..fd47ce77 100644 --- a/sope-core/NGExtensions/NGExtensions/NGLogging.h +++ b/sope-core/NGExtensions/NGExtensions/NGLogging.h @@ -33,8 +33,9 @@ #include #include #include +#include #include -#include +#include #include #endif /* __NGExtensions_NGLogging_H_ */ diff --git a/sope-core/NGExtensions/NGLogging.subproj/ChangeLog b/sope-core/NGExtensions/NGLogging.subproj/ChangeLog index 5a13bd65..de3b0e80 100644 --- a/sope-core/NGExtensions/NGLogging.subproj/ChangeLog +++ b/sope-core/NGExtensions/NGLogging.subproj/ChangeLog @@ -1,3 +1,33 @@ +2004-11-19 Marcus Mueller + + * *.h: added detailed documentation + + * *.m: added -description where appropriate + + * NGLogger.m: removed +defaultLogger from the API, it's used + internally though. + + * NGLoggerManager.m: reinstated caching of loggers. Added optimization + to reuse a "default" logger when no config is available. + + * NGLogEvent.[hm]: changed -date to return NSCalendarDate instead of + NSDate. + + * NGLogEventFormatter.[hm]: new base class for implementing formatters. + Also offers a factory for creating log event formatter instances + from configurations. + + * NGLogEventDetailedFormatter.m: offers rich logging, similar to what + NSLog() in libFoundation has to offer. + + * NGLogConsoleAppender.m: removed, obsoleted by NGLogStdoutAppender. + + * NGLogFileHandleAppender.[hm]: new base class for implementing file + handle based appenders. + + * NGLogStdoutAppender.m, NGLogStderrAppender.m: appenders for logging + to stdout/stderr. + 2004-11-19 Helge Hess * NGLoggerManager.m: use default logger if none is registered diff --git a/sope-core/NGExtensions/NGLogging.subproj/GNUmakefile b/sope-core/NGExtensions/NGLogging.subproj/GNUmakefile index d90f37a2..817dfece 100644 --- a/sope-core/NGExtensions/NGLogging.subproj/GNUmakefile +++ b/sope-core/NGExtensions/NGLogging.subproj/GNUmakefile @@ -9,8 +9,12 @@ NGLogging_OBJC_FILES += \ NGLogger.m \ NGLoggerManager.m \ NGLogEvent.m \ + NGLogEventFormatter.m \ + NGLogEventDetailedFormatter.m \ NGLogAppender.m \ - NGLogConsoleAppender.m \ + NGLogFileHandleAppender.m \ + NGLogStdoutAppender.m \ + NGLogStderrAppender.m \ # TODO: disable on Windows NGLogging_OBJC_FILES += \ diff --git a/sope-core/NGExtensions/NGLogging.subproj/NGLogAppender.m b/sope-core/NGExtensions/NGLogging.subproj/NGLogAppender.m index 324315ea..d1dd8319 100644 --- a/sope-core/NGExtensions/NGLogging.subproj/NGLogAppender.m +++ b/sope-core/NGExtensions/NGLogging.subproj/NGLogAppender.m @@ -22,10 +22,58 @@ #include "NGLogAppender.h" #include "NGLogLevel.h" #include "NGLogEvent.h" +#include "NGLogEventFormatter.h" #include "common.h" @implementation NGLogAppender +static NSString *defaultAppenderClassName = nil; + ++ (void)initialize { + static BOOL didInit = NO; + NSUserDefaults *ud; + + if (didInit) return; + + didInit = YES; + ud = [NSUserDefaults standardUserDefaults]; + defaultAppenderClassName = + [[ud stringForKey:@"NGLogDefaultAppenderClass"] retain]; + if (defaultAppenderClassName == nil) + defaultAppenderClassName = @"NGLogStdoutAppender"; +} + ++ (id)logAppenderFromConfig:(NSDictionary *)_config { + NSString *className; + Class clazz; + id appender; + + className = [_config objectForKey:@"Class"]; + if (!className) + className = defaultAppenderClassName; + clazz = NSClassFromString(className); + if (clazz == Nil) { + NSLog(@"ERROR: can't instantiate appender class named '%@'", + className); + return nil; + } + appender = [[[clazz alloc] initWithConfig:_config] autorelease]; + return appender; +} + +- (id)initWithConfig:(NSDictionary *)_config { + self = [super init]; + if (self) { + NSDictionary *formatterConfig; + + formatterConfig = [_config objectForKey:@"Formatter"]; + self->formatter = + [[NGLogEventFormatter logEventFormatterFromConfig:formatterConfig] + retain]; + } + return self; +} + - (void)appendLogEvent:(NGLogEvent *)_event { #if LIB_FOUNDATION_LIBRARY [self subclassResponsibility:_cmd]; @@ -35,39 +83,10 @@ #endif } -- (NSString *)formattedEvent:(NGLogEvent *)_event { - NSMutableString *fe; - NSString *lvl; - - lvl = [self localizedNameOfLogLevel:[_event level]]; - fe = [NSMutableString stringWithCapacity:128]; - if (lvl != nil) { - [fe appendString:@"["]; - [fe appendString:lvl]; - [fe appendString:@"] "]; - } - [fe appendString:[_event message]]; - return fe; -} +/* formatting */ -- (NSString *)localizedNameOfLogLevel:(NGLogLevel)_level { - NSString *name; - - switch (_level) { - case NGLogLevelWarn: - name = @"WARN"; - break; - case NGLogLevelError: - name = @"ERROR"; - break; - case NGLogLevelFatal: - name = @"FATAL"; - break; - default: - name = nil; - break; - } - return name; +- (NSString *)formattedEvent:(NGLogEvent *)_event { + return [self->formatter formattedEvent:_event]; } @end /* NGLogAppender */ diff --git a/sope-core/NGExtensions/NGLogging.subproj/NGLogConsoleAppender.m b/sope-core/NGExtensions/NGLogging.subproj/NGLogConsoleAppender.m deleted file mode 100644 index 645dea4c..00000000 --- a/sope-core/NGExtensions/NGLogging.subproj/NGLogConsoleAppender.m +++ /dev/null @@ -1,90 +0,0 @@ -/* - Copyright (C) 2004 SKYRIX Software AG - - This file is part of OpenGroupware.org. - - OGo is free software; you can redistribute it and/or modify it under - the terms of the GNU Lesser General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - OGo is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with OGo; see the file COPYING. If not, write to the - Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. -*/ - -#include "NGLogConsoleAppender.h" -#include "NGLogEvent.h" -#include "common.h" -#include -#include - -@implementation NGLogConsoleAppender - -static Class NSCalendarDateClass = Nil; -static Class NSProcessInfoClass = Nil; -static unsigned char *processName = NULL; - -static char *monthNames[14] = { - "Dec", - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", - "Jan" -}; - -+ (void)initialize { - if (NSCalendarDateClass == Nil) - NSCalendarDateClass = [NSCalendarDate class]; - if (NSProcessInfoClass == Nil) - NSProcessInfoClass = [NSProcessInfo class]; - - if (processName == NULL) { - /* process name can't change, right? */ - unsigned len; - NSString *pn; - - pn = [[NSProcessInfoClass processInfo] processName]; - len = [pn cStringLength]; - - processName = malloc(len + 4); - [pn getCString:processName]; - } -} - -static __inline__ unsigned char * levelPrefixForEvent(NGLogEvent *_event) { - switch ([_event level]) { - case NGLogLevelWarn: return "[WARN]"; - case NGLogLevelError: return "[ERROR]"; - case NGLogLevelFatal: return "[FATAL]"; - default: return ""; - } -} - -- (void)appendLogEvent:(NGLogEvent *)_event { - /* Note: pid can change after a fork() */ - NSCalendarDate *date; - - // TODO: get time using libc function, cheaper - // TODO: set to GMT? - date = [[NSCalendarDateClass alloc] init]; - - // TODO: cString for message is expensive - fprintf(stderr, - "%s %02i %02i:%02i:%02i %s [%d]: %s\n", - monthNames[[date monthOfYear]], - [date dayOfMonth], - [date hourOfDay], [date minuteOfHour], [date secondOfMinute], - processName, - getpid(), - [[_event message] cString]); - - [date release]; -} - -@end /* NGLogConsoleAppender */ diff --git a/sope-core/NGExtensions/NGLogging.subproj/NGLogEvent.m b/sope-core/NGExtensions/NGLogging.subproj/NGLogEvent.m index 3de406bd..b1d366ff 100644 --- a/sope-core/NGExtensions/NGLogging.subproj/NGLogEvent.m +++ b/sope-core/NGExtensions/NGLogging.subproj/NGLogEvent.m @@ -24,24 +24,30 @@ @implementation NGLogEvent -static Class NSDateClass = Nil; +static Class DateClass = Nil; + (void)initialize { - NSDateClass = [NSDate class]; + static BOOL didInit = NO; + + if (didInit) return; + didInit = YES; + + DateClass = [NSCalendarDate class]; } - (id)initWithLevel:(NGLogLevel)_level message:(NSString *)_msg { self = [super init]; - if(self) { - self->date = [NSDateClass timeIntervalSinceReferenceDate]; - self->level = _level; - self->msg = [_msg copy]; + if (self) { + // TODO: get time using libc function, cheaper + self->date = [DateClass timeIntervalSinceReferenceDate]; + self->level = _level; + self->msg = [_msg copy]; } return self; } - (void)dealloc { - [self->msg release]; + [self->msg release]; [super dealloc]; } @@ -55,8 +61,28 @@ static Class NSDateClass = Nil; return self->msg; } -- (NSDate *)date { - return [NSDateClass dateWithTimeIntervalSinceReferenceDate:self->date]; +- (NSCalendarDate *)date { + // TODO: set to GMT? + return [DateClass dateWithTimeIntervalSinceReferenceDate:self->date]; +} + +/* description */ + +- (NSString *)description { + NSString *lvl; + + switch (self->level) { + case NGLogLevelOff: lvl = @"OFF"; break; + case NGLogLevelDebug: lvl = @"DEBUG"; break; + case NGLogLevelInfo: lvl = @"INFO"; break; + case NGLogLevelWarn: lvl = @"WARN"; break; + case NGLogLevelError: lvl = @"ERROR"; break; + case NGLogLevelFatal: lvl = @"FATAL"; break; + default: lvl = @"ALL"; break; + } + return [NSString stringWithFormat:@"<%@[0x%08X] date=%@ level=%@ msg:%@>", + NSStringFromClass([self class]), self, + [self date], lvl, self->msg]; } @end /* NGLogEvent */ diff --git a/sope-core/NGExtensions/NGLogging.subproj/NGLogEventDetailedFormatter.m b/sope-core/NGExtensions/NGLogging.subproj/NGLogEventDetailedFormatter.m new file mode 100644 index 00000000..e5531a8b --- /dev/null +++ b/sope-core/NGExtensions/NGLogging.subproj/NGLogEventDetailedFormatter.m @@ -0,0 +1,100 @@ +/* + Copyright (C) 2000-2004 SKYRIX Software AG + + This file is part of OGo + + OGo is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + OGo is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with OGo; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ +// $Id$ + + +#include "NGLogEventFormatter.h" +#include "NGLogLevel.h" + +@class NSString; + +@interface NGLogEventDetailedFormatter : NGLogEventFormatter +{ +} + +@end + +#include "NGLogEvent.h" +#include "common.h" +#include "NSProcessInfo+misc.h" + +@implementation NGLogEventDetailedFormatter + +static unsigned char *processName = NULL; +static NSProcessInfo *processInfo = nil; + +static char *monthNames[14] = { + "Dec", + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + "Jan" +}; + ++ (void)initialize { + static BOOL didInit = NO; + unsigned len; + NSString *pn; + + if (didInit) return; + + didInit = YES; + processInfo = [[NSProcessInfo processInfo] retain]; + pn = [processInfo processName]; + len = [pn cStringLength]; + processName = malloc(len + 4); + [pn getCString:processName]; +} + +static __inline__ unsigned char * levelPrefixForEvent(NGLogEvent *_event) { + switch ([_event level]) { + case NGLogLevelWarn: return "[WARN] "; + case NGLogLevelError: return "[ERROR] "; + case NGLogLevelFatal: return "[FATAL] "; + default: return ""; + } +} + +- (NSString *)formattedEvent:(NGLogEvent *)_event { + NSMutableString *fe; + NSCalendarDate *date; + + fe = [NSMutableString stringWithCapacity:160]; + /* timestamp, process name, process id, level prefix */ + date = [_event date]; + [fe appendFormat:@"%s %02i %02i:%02i:%02i %s [%d]: %s", + monthNames[[date monthOfYear]], + [date dayOfMonth], + [date hourOfDay], [date minuteOfHour], [date secondOfMinute], + processName, + /* Note: pid can change after a fork() */ +#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY + [processInfo processIdentifier], +#else + [[processInfo processId] intValue], +#endif + levelPrefixForEvent(_event)]; + + /* message */ + [fe appendString:[_event message]]; + return fe; +} + +@end /* NGLogEventDetailedFormatter */ diff --git a/sope-core/NGExtensions/NGLogging.subproj/NGLogEventFormatter.m b/sope-core/NGExtensions/NGLogging.subproj/NGLogEventFormatter.m new file mode 100644 index 00000000..bf071b90 --- /dev/null +++ b/sope-core/NGExtensions/NGLogging.subproj/NGLogEventFormatter.m @@ -0,0 +1,75 @@ +/* + Copyright (C) 2000-2004 SKYRIX Software AG + + This file is part of OGo + + OGo is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + OGo is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with OGo; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#include "NGLogEventFormatter.h" +#include "NGLogEvent.h" +#include "common.h" + +@implementation NGLogEventFormatter + +static NSString *defaultFormatterClassName = nil; + ++ (void)initialize { + static BOOL didInit = NO; + NSUserDefaults *ud; + + if (didInit) return; + + didInit = YES; + ud = [NSUserDefaults standardUserDefaults]; + defaultFormatterClassName = + [[ud stringForKey:@"NGLogDefaultLogEventFormatterClass"] retain]; + if (defaultFormatterClassName == nil) + defaultFormatterClassName = @"NGLogEventFormatter"; +} + ++ (id)logEventFormatterFromConfig:(NSDictionary *)_config { + NSString *className; + Class clazz; + id formatter; + + className = [_config objectForKey:@"Class"]; + if (!className) + className = defaultFormatterClassName; + clazz = NSClassFromString(className); + if (clazz == Nil) { + NSLog(@"ERROR: can't instantiate log event formatter class named '%@'", + className); + return nil; + } + formatter = [[[clazz alloc] initWithConfig:_config] autorelease]; + return formatter; +} + +- (id)initWithConfig:(NSDictionary *)_config { + self = [super init]; + if (self) { + } + return self; +} + +/* formatting */ + +- (NSString *)formattedEvent:(NGLogEvent *)_event { + return [_event message]; +} + +@end /* NGLogEventFormatter */ diff --git a/sope-core/NGExtensions/NGLogging.subproj/NGLogFileHandleAppender.m b/sope-core/NGExtensions/NGLogging.subproj/NGLogFileHandleAppender.m new file mode 100644 index 00000000..62dee3cf --- /dev/null +++ b/sope-core/NGExtensions/NGLogging.subproj/NGLogFileHandleAppender.m @@ -0,0 +1,79 @@ +/* + Copyright (C) 2004 SKYRIX Software AG + + This file is part of OpenGroupware.org. + + OGo is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + OGo is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with OGo; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#include "NGLogFileHandleAppender.h" +#include "NGLogEvent.h" +#include "common.h" + +@implementation NGLogFileHandleAppender + +static NSData *nextLineData = nil; + ++ (void)initialize { + static BOOL didInit = NO; + + if (didInit) return; + + didInit = YES; + nextLineData = [[@"\n" dataUsingEncoding:NSASCIIStringEncoding] retain]; +} + +- (id)initWithConfig:(NSDictionary *)_config { + self = [super initWithConfig:_config]; + if (self) { + self->flushImmediately = NO; + self->encoding = [NSString defaultCStringEncoding]; + [self openFileHandleWithConfig:_config]; + } + return self; +} + +- (void)dealloc { + if ([self isFileHandleOpen]) + [self closeFileHandle]; + [self->fh release]; + [super dealloc]; +} + +- (BOOL)isFileHandleOpen { + return self->fh ? YES : NO; +} + +- (void)openFileHandleWithConfig:(NSDictionary *)_config { +} + +- (void)closeFileHandle { + [self->fh closeFile]; +} + +- (void)appendLogEvent:(NGLogEvent *)_event { + NSString *formatted; + NSData *bin; + + formatted = [self formattedEvent:_event]; + bin = [formatted dataUsingEncoding:self->encoding]; + [self->fh writeData:bin]; + [self->fh writeData:nextLineData]; + if (self->flushImmediately) + [self->fh synchronizeFile]; +} + +@end /* NGLogFileHandleAppender */ diff --git a/sope-core/NGExtensions/NGLogging.subproj/NGLogStderrAppender.m b/sope-core/NGExtensions/NGLogging.subproj/NGLogStderrAppender.m new file mode 100644 index 00000000..f0742282 --- /dev/null +++ b/sope-core/NGExtensions/NGLogging.subproj/NGLogStderrAppender.m @@ -0,0 +1,38 @@ +/* + Copyright (C) 2004 SKYRIX Software AG + + This file is part of OpenGroupware.org. + + OGo is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + OGo is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with OGo; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +#include "NGLogFileHandleAppender.h" + +@interface NGLogStderrAppender : NGLogFileHandleAppender +{ +} + +@end + +#include "common.h" + +@implementation NGLogStderrAppender + +- (void)openFileHandleWithConfig:(NSDictionary *)_config { + self->fh = [[NSFileHandle fileHandleWithStandardError] retain]; +} + +@end /* NGLogStderrAppender */ diff --git a/sope-core/NGExtensions/NGExtensions/NGLogConsoleAppender.h b/sope-core/NGExtensions/NGLogging.subproj/NGLogStdoutAppender.m similarity index 60% rename from sope-core/NGExtensions/NGExtensions/NGLogConsoleAppender.h rename to sope-core/NGExtensions/NGLogging.subproj/NGLogStdoutAppender.m index 2fca9c9c..906e713f 100644 --- a/sope-core/NGExtensions/NGExtensions/NGLogConsoleAppender.h +++ b/sope-core/NGExtensions/NGLogging.subproj/NGLogStdoutAppender.m @@ -19,24 +19,20 @@ 02111-1307, USA. */ -#ifndef __NGExtensions_NGLogConsoleAppender_H_ -#define __NGExtensions_NGLogConsoleAppender_H_ +#include "NGLogFileHandleAppender.h" -/* - NGLogConsoleAppender - - A very simple console appender. The current implementation logs the - formatted event via NSLog(). Please note that doing so discards the timestamp - saved in the event, so the logged time isn't really exact, but will probably - only differ marginally. -*/ - -#include - -@interface NGLogConsoleAppender : NGLogAppender +@interface NGLogStdoutAppender : NGLogFileHandleAppender { } @end -#endif /* __NGExtensions_NGLogConsoleAppender_H_ */ +#include "common.h" + +@implementation NGLogStdoutAppender + +- (void)openFileHandleWithConfig:(NSDictionary *)_config { + self->fh = [[NSFileHandle fileHandleWithStandardOutput] retain]; +} + +@end /* NGLogStdoutAppender */ diff --git a/sope-core/NGExtensions/NGLogging.subproj/NGLogSyslogAppender.m b/sope-core/NGExtensions/NGLogging.subproj/NGLogSyslogAppender.m index 1bb3be11..ba0884d7 100644 --- a/sope-core/NGExtensions/NGLogging.subproj/NGLogSyslogAppender.m +++ b/sope-core/NGExtensions/NGLogging.subproj/NGLogSyslogAppender.m @@ -55,8 +55,13 @@ static NSString *defaultSyslogIdentifier = nil; return sharedAppender; } -- (id)init { - return [self initWithIdentifier:defaultSyslogIdentifier]; +- (id)initWithConfig:(NSDictionary *)_config { + NSString *identifier; + + identifier = [_config objectForKey:@"SyslogIdentifier"]; + if(!identifier) + identifier = defaultSyslogIdentifier; + return [self initWithIdentifier:identifier]; } - (id)initWithIdentifier:(NSString *)_ident { diff --git a/sope-core/NGExtensions/NGLogging.subproj/NGLogger.m b/sope-core/NGExtensions/NGLogging.subproj/NGLogger.m index fd746406..09b814fd 100644 --- a/sope-core/NGExtensions/NGLogging.subproj/NGLogger.m +++ b/sope-core/NGExtensions/NGLogging.subproj/NGLogger.m @@ -20,67 +20,101 @@ */ #include "NGLogger.h" -#include "common.h" #include "NGLogEvent.h" #include "NGLogAppender.h" +#include "NSNull+misc.h" +#include "common.h" @interface NGLogger (PrivateAPI) -- (void)logLevel:(NGLogLevel)_level message:(NSString *)_msg; -- (void)logLevel:(NGLogLevel)_level withFormat:(NSString *)_fmt, ...; ++ (NGLogLevel)_logLevelForString:(NSString *)_level; @end @implementation NGLogger -static Class NSStringClass = Nil; +static Class NSStringClass = Nil; +static NGLogger *defaultLogger = nil; +static NGLogLevel defaultLogLevel = NGLogLevelInfo; + (void)initialize { - static BOOL didInit = NO; - if (didInit) - return; - didInit = YES; - NSStringClass = [NSString class]; + static BOOL didInit = NO; + NSUserDefaults *ud; + NSString *level; + + if (didInit) return; + + didInit = YES; + NSStringClass = [NSString class]; + ud = [NSUserDefaults standardUserDefaults]; + level = [ud stringForKey:@"NGLogDefaultLogLevel"]; + defaultLogLevel = [self _logLevelForString:level]; + defaultLogger = [[self alloc] init]; } -+ (id)defaultLogger { - static NGLogger *logger = nil; // THREAD - - if (logger == nil) - logger = [[self alloc] init]; ++ (id)loggerWithConfigFromUserDefaults:(NSString *)_defaultName { + NSUserDefaults *ud; + NSDictionary *config; + id logger; + + ud = [NSUserDefaults standardUserDefaults]; + config = [ud dictionaryForKey:_defaultName]; + if(!config) + return defaultLogger; + logger = [[[NGLogger alloc] initWithConfig:config] autorelease]; return logger; } - (id)init { - return [self initWithLogLevel:NGLogLevelAll]; + return [self initWithConfig:nil]; } -- (id)initWithLogLevel:(NGLogLevel)_level appender:(id)_appenderParam { - if ((self = [super init]) != nil) { - [self setLogLevel:_level]; - self->_appender = [_appenderParam retain]; // TODO: fix ivar name +- (id)initWithConfig:(NSDictionary *)_config { + self = [super init]; + if (self) { + NSArray *appenderConfigs; + NGLogAppender *appender; + NSString *levelString; + NGLogLevel level; + unsigned count; + + self->appenders = [[NSMutableArray alloc] initWithCapacity:1]; + + levelString = [_config objectForKey:@"LogLevel"]; + level = [NGLogger _logLevelForString:levelString]; + [self setLogLevel:level]; + + appenderConfigs = [_config objectForKey:@"Appenders"]; + count = [appenderConfigs count]; + if(!count) { + /* create a default appender */ + appender = [NGLogAppender logAppenderFromConfig:nil]; + [self addAppender:appender]; + } + else { + unsigned i; + + for(i = 0; i < count; i++) { + NSDictionary *appenderConfig; + + appenderConfig = [appenderConfigs objectAtIndex:i]; + appender = [NGLogAppender logAppenderFromConfig:appenderConfig]; + if(appender) + [self addAppender:appender]; + } + } } return self; } - (id)initWithLogLevel:(NGLogLevel)_level { - NSUserDefaults *ud; - NSString *appenderClassName; - id appender; - - // TODO: remove this as soon as we have a config - ud = [NSUserDefaults standardUserDefaults]; - appenderClassName = [ud stringForKey:@"NGLogDefaultAppenderClass"]; - if (appenderClassName == nil) - appenderClassName = @"NGLogConsoleAppender"; - - appender = [[NSClassFromString(appenderClassName) alloc] init]; - - self = [self initWithLogLevel:_level appender:appender]; - [appender release]; + self = [self initWithConfig:nil]; + if (self) { + [self setLogLevel:_level]; + } return self; } - (void)dealloc { - [self->_appender release]; + [self->appenders release]; [super dealloc]; } @@ -93,6 +127,14 @@ static Class NSStringClass = Nil; return self->logLevel; } +- (void)addAppender:(NGLogAppender *)_appender { + [self->appenders addObject:_appender]; +} + +- (void)removeAppender:(NGLogAppender *)_appender { + [self->appenders removeObject:_appender]; +} + /* logging */ - (void)debugWithFormat:(NSString *)_fmt arguments:(va_list)_va { @@ -147,12 +189,17 @@ static Class NSStringClass = Nil; - (void)logLevel:(NGLogLevel)_level message:(NSString *)_msg { NGLogEvent *event; + unsigned i, count; event = [[NGLogEvent alloc] initWithLevel:_level message:_msg]; - // iterate appenders - // TODO: as soon as we have more appenders, we need to iterate on them - [self->_appender appendLogEvent:event]; + count = [self->appenders count]; + for(i = 0; i < count; i++) { + NGLogAppender *appender; + + appender = [self->appenders objectAtIndex:i]; + [appender appendLogEvent:event]; + } [event release]; } @@ -174,4 +221,44 @@ static Class NSStringClass = Nil; return self->logLevel >= NGLogLevelFatal; } + +/* Private */ + ++ (NGLogLevel)_logLevelForString:(NSString *)_level { + if (![_level isNotNull]) { + _level = [_level uppercaseString]; + if ([_level isEqualToString:@"DEBUG"]) + return NGLogLevelDebug; + else if ([_level isEqualToString:@"INFO"]) + return NGLogLevelInfo; + else if ([_level isEqualToString:@"WARN"]) + return NGLogLevelWarn; + else if ([_level isEqualToString:@"ERROR"]) + return NGLogLevelError; + else if ([_level isEqualToString:@"FATAL"]) + return NGLogLevelFatal; + return NGLogLevelAll; /* better than nothing */ + } + return NGLogLevelInfo; +} + +/* description */ + +- (NSString *)description { + NSString *lvl; + + switch (self->logLevel) { + case NGLogLevelOff: lvl = @"OFF"; break; + case NGLogLevelDebug: lvl = @"DEBUG"; break; + case NGLogLevelInfo: lvl = @"INFO"; break; + case NGLogLevelWarn: lvl = @"WARN"; break; + case NGLogLevelError: lvl = @"ERROR"; break; + case NGLogLevelFatal: lvl = @"FATAL"; break; + default: lvl = @"ALL"; break; + } + return [NSString stringWithFormat:@"<%@[0x%08X] logLevel=%@ appenders:%@>", + NSStringFromClass([self class]), self, + lvl, self->appenders]; +} + @end /* NGLogger */ diff --git a/sope-core/NGExtensions/NGLogging.subproj/NGLoggerManager.m b/sope-core/NGExtensions/NGLogging.subproj/NGLoggerManager.m index 550ed3df..c51b37eb 100644 --- a/sope-core/NGExtensions/NGLogging.subproj/NGLoggerManager.m +++ b/sope-core/NGExtensions/NGLogging.subproj/NGLoggerManager.m @@ -22,22 +22,30 @@ #include "NGLoggerManager.h" #include "NGLogLevel.h" #include "NGLogger.h" +#include "NSNull+misc.h" #include "common.h" +@interface NGLoggerManager (PrivateAPI) +- (NGLogger *)_getConfiguredLoggerNamed:(NSString *)_name; +@end + @implementation NGLoggerManager -static NGLoggerManager *sharedInstance; -static NSNull *sharedNull; +static NGLoggerManager *sharedInstance = nil; +static NSNull *sharedNull = nil; +static BOOL debugAll = NO; + (void)initialize { - static BOOL didInit = NO; - - if (didInit) - return; + static BOOL didInit = NO; + NSUserDefaults *ud; + + if (didInit) return; - didInit = YES; - sharedInstance = [[self alloc] init]; - sharedNull = [[NSNull null] retain]; + didInit = YES; + sharedInstance = [[self alloc] init]; + sharedNull = [[NSNull null] retain]; + ud = [NSUserDefaults standardUserDefaults]; + debugAll = [ud boolForKey:@"NGLogDebugAllEnabled"]; } + (id)defaultLoggerManager { @@ -71,28 +79,26 @@ static NSNull *sharedNull; NSUserDefaults *ud; ud = [NSUserDefaults standardUserDefaults]; - if (![ud boolForKey:_defaultKey]) { + if (!debugAll && ![ud boolForKey:_defaultKey]) { [self->loggerMap setObject:sharedNull forKey:_defaultKey]; logger = sharedNull; } else { - logger = [[NGLogger alloc] initWithLogLevel:NGLogLevelDebug]; + logger = [self _getConfiguredLoggerNamed:_defaultKey]; [self->loggerMap setObject:logger forKey:_defaultKey]; - [logger release]; } } return (logger != sharedNull) ? logger : nil; } - (NGLogger *)loggerForFacilityNamed:(NSString *)_name { - id logger; + NGLogger *logger; // TODO: expensive, use a faster map (at least NSMapTable) if ((logger = [self->loggerMap objectForKey:_name]) != nil) return logger; - - // TODO: is a registration really faster? I guess not? - logger = [NGLogger defaultLogger]; /* fallback to shared logger */ + + logger = [self _getConfiguredLoggerNamed:_name]; [self->loggerMap setObject:logger forKey:_name]; return logger; } @@ -104,4 +110,21 @@ static NSNull *sharedNull; return [self loggerForFacilityNamed:name]; } +/* Private */ + +- (NGLogger *)_getConfiguredLoggerNamed:(NSString *)_name { + NSString *configKey; + + configKey = [NSString stringWithFormat:@"%@LoggerConfig", _name]; + return [NGLogger loggerWithConfigFromUserDefaults:configKey]; +} + +/* description */ + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@[0x%08X] debugAll=%@ #loggers=%d>", + NSStringFromClass([self class]), self, + debugAll ? @"YES" : @"NO", [self->loggerMap count]]; +} + @end /* NGLoggerManager */ diff --git a/sope-core/NGExtensions/Version b/sope-core/NGExtensions/Version index 38af7b35..0ed06f52 100644 --- a/sope-core/NGExtensions/Version +++ b/sope-core/NGExtensions/Version @@ -1,6 +1,6 @@ # version -SUBMINOR_VERSION:=135 +SUBMINOR_VERSION:=136 # v4.3.115 requires libFoundation v1.0.59 # v4.2.72 requires libEOControl v4.2.39