aboutsummaryrefslogtreecommitdiffhomepage
path: root/GoogleUtilities/Logger
diff options
context:
space:
mode:
authorGravatar Paul Beusterien <paulbeusterien@google.com>2018-07-11 08:28:35 -0700
committerGravatar GitHub <noreply@github.com>2018-07-11 08:28:35 -0700
commitc6b4b03fffc3cea7c9525e5c79dce28f52900521 (patch)
tree0e8a237940dcd4b4100c00b9fac428e657619ab8 /GoogleUtilities/Logger
parent25f8691970a9f765a87ab3125776598c92e02744 (diff)
Move GoogleUtilities out of Firebase directory (#1516)
Diffstat (limited to 'GoogleUtilities/Logger')
-rw-r--r--GoogleUtilities/Logger/GULLogger.m214
-rw-r--r--GoogleUtilities/Logger/Private/GULLogger.h151
-rw-r--r--GoogleUtilities/Logger/Public/GULLoggerLevel.h35
3 files changed, 400 insertions, 0 deletions
diff --git a/GoogleUtilities/Logger/GULLogger.m b/GoogleUtilities/Logger/GULLogger.m
new file mode 100644
index 0000000..5c808ea
--- /dev/null
+++ b/GoogleUtilities/Logger/GULLogger.m
@@ -0,0 +1,214 @@
+// Copyright 2018 Google
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#import "Private/GULLogger.h"
+
+#include <asl.h>
+
+#import <GoogleUtilities/GULAppEnvironmentUtil.h>
+#import "Public/GULLoggerLevel.h"
+
+/// Key for the debug mode bit in NSUserDefaults.
+NSString *const kGULPersistedDebugModeKey = @"/google/utilities/debug_mode";
+
+/// ASL client facility name used by GULLogger.
+const char *kGULLoggerASLClientFacilityName = "com.google.utilities.logger";
+
+static dispatch_once_t sGULLoggerOnceToken;
+
+static aslclient sGULLoggerClient;
+
+static dispatch_queue_t sGULClientQueue;
+
+static BOOL sGULLoggerDebugMode;
+
+static GULLoggerLevel sGULLoggerMaximumLevel;
+
+// Allow clients to register a version to include in the log.
+static const char *sVersion = "";
+
+static GULLoggerService kGULLoggerLogger = @"[GULLogger]";
+
+#ifdef DEBUG
+/// The regex pattern for the message code.
+static NSString *const kMessageCodePattern = @"^I-[A-Z]{3}[0-9]{6}$";
+static NSRegularExpression *sMessageCodeRegex;
+#endif
+
+void GULLoggerInitializeASL(BOOL overrideSTDERR, BOOL forceDebugMode) {
+ dispatch_once(&sGULLoggerOnceToken, ^{
+ NSInteger majorOSVersion = [[GULAppEnvironmentUtil systemVersion] integerValue];
+ uint32_t aslOptions = ASL_OPT_STDERR;
+#if TARGET_OS_SIMULATOR
+ // The iOS 11 simulator doesn't need the ASL_OPT_STDERR flag.
+ if (majorOSVersion >= 11) {
+ aslOptions = 0;
+ }
+#else
+ // Devices running iOS 10 or higher don't need the ASL_OPT_STDERR flag.
+ if (majorOSVersion >= 10) {
+ aslOptions = 0;
+ }
+#endif // TARGET_OS_SIMULATOR
+
+ // Override the aslOptions to ASL_OPT_STDERR if the override argument is passed in.
+ if (overrideSTDERR) {
+ aslOptions = ASL_OPT_STDERR;
+ }
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations" // asl is deprecated
+ // Initialize the ASL client handle.
+ sGULLoggerClient = asl_open(NULL, kGULLoggerASLClientFacilityName, aslOptions);
+ sGULLoggerDebugMode = forceDebugMode;
+ sGULLoggerMaximumLevel = GULLoggerLevelNotice;
+
+ if (forceDebugMode) {
+ asl_set_filter(sGULLoggerClient, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
+ } else {
+ // Set the filter used by system/device log. Initialize in default mode.
+ asl_set_filter(sGULLoggerClient, ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE));
+ }
+
+ // We should disable debug mode if we are running from App Store.
+ if (sGULLoggerDebugMode && [GULAppEnvironmentUtil isFromAppStore]) {
+ sGULLoggerDebugMode = NO;
+ }
+
+ sGULClientQueue = dispatch_queue_create("GULLoggingClientQueue", DISPATCH_QUEUE_SERIAL);
+ dispatch_set_target_queue(sGULClientQueue,
+ dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));
+
+#ifdef DEBUG
+ sMessageCodeRegex =
+ [NSRegularExpression regularExpressionWithPattern:kMessageCodePattern options:0 error:NULL];
+#endif
+ });
+}
+
+void GULSetLoggerLevel(GULLoggerLevel loggerLevel) {
+ if (loggerLevel < GULLoggerLevelMin || loggerLevel > GULLoggerLevelMax) {
+ GULLogError(kGULLoggerLogger, NO, @"I-COR000023", @"Invalid logger level, %ld",
+ (long)loggerLevel);
+ return;
+ }
+ GULLoggerInitializeASL(NO, NO);
+ // We should not raise the logger level if we are running from App Store.
+ if (loggerLevel >= GULLoggerLevelNotice && [GULAppEnvironmentUtil isFromAppStore]) {
+ return;
+ }
+
+ sGULLoggerMaximumLevel = loggerLevel;
+ dispatch_async(sGULClientQueue, ^{
+ asl_set_filter(sGULLoggerClient, ASL_FILTER_MASK_UPTO(loggerLevel));
+ });
+}
+
+/**
+ * Check if the level is high enough to be loggable.
+ */
+__attribute__((no_sanitize("thread"))) BOOL GULIsLoggableLevel(GULLoggerLevel loggerLevel) {
+ GULLoggerInitializeASL(NO, NO);
+ if (sGULLoggerDebugMode) {
+ return YES;
+ }
+ return (BOOL)(loggerLevel <= sGULLoggerMaximumLevel);
+}
+
+#ifdef DEBUG
+void GULResetLogger() {
+ sGULLoggerOnceToken = 0;
+}
+
+aslclient getGULLoggerClient() {
+ return sGULLoggerClient;
+}
+
+dispatch_queue_t getGULClientQueue() {
+ return sGULClientQueue;
+}
+
+BOOL getGULLoggerDebugMode() {
+ return sGULLoggerDebugMode;
+}
+#endif
+
+void GULLoggerRegisterVersion(const char *version) {
+ sVersion = version;
+}
+
+void GULLogBasic(GULLoggerLevel level,
+ GULLoggerService service,
+ BOOL forceLog,
+ NSString *messageCode,
+ NSString *message,
+ va_list args_ptr) {
+ GULLoggerInitializeASL(NO, NO);
+ if (!(level <= sGULLoggerMaximumLevel || sGULLoggerDebugMode || forceLog)) {
+ return;
+ }
+
+#ifdef DEBUG
+ NSCAssert(messageCode.length == 11, @"Incorrect message code length.");
+ NSRange messageCodeRange = NSMakeRange(0, messageCode.length);
+ NSUInteger numberOfMatches =
+ [sMessageCodeRegex numberOfMatchesInString:messageCode options:0 range:messageCodeRange];
+ NSCAssert(numberOfMatches == 1, @"Incorrect message code format.");
+#endif
+ NSString *logMsg = [[NSString alloc] initWithFormat:message arguments:args_ptr];
+ logMsg = [NSString stringWithFormat:@"%s - %@[%@] %@", sVersion, service, messageCode, logMsg];
+ dispatch_async(sGULClientQueue, ^{
+ asl_log(sGULLoggerClient, NULL, level, "%s", logMsg.UTF8String);
+ });
+}
+#pragma clang diagnostic pop
+
+/**
+ * Generates the logging functions using macros.
+ *
+ * Calling GULLogError(kGULLoggerCore, @"I-COR000001", @"Configure %@ failed.", @"blah") shows:
+ * yyyy-mm-dd hh:mm:ss.SSS sender[PID] <Error> [{service}][I-COR000001] Configure blah failed.
+ * Calling GULLogDebug(kGULLoggerCore, @"I-COR000001", @"Configure succeed.") shows:
+ * yyyy-mm-dd hh:mm:ss.SSS sender[PID] <Debug> [{service}][I-COR000001] Configure succeed.
+ */
+#define GUL_LOGGING_FUNCTION(level) \
+ void GULLog##level(GULLoggerService service, BOOL force, NSString *messageCode, \
+ NSString *message, ...) { \
+ va_list args_ptr; \
+ va_start(args_ptr, message); \
+ GULLogBasic(GULLoggerLevel##level, service, force, messageCode, message, args_ptr); \
+ va_end(args_ptr); \
+ }
+
+GUL_LOGGING_FUNCTION(Error)
+GUL_LOGGING_FUNCTION(Warning)
+GUL_LOGGING_FUNCTION(Notice)
+GUL_LOGGING_FUNCTION(Info)
+GUL_LOGGING_FUNCTION(Debug)
+
+#undef GUL_MAKE_LOGGER
+
+#pragma mark - GULLoggerWrapper
+
+@implementation GULLoggerWrapper
+
++ (void)logWithLevel:(GULLoggerLevel)level
+ withService:(GULLoggerService)service
+ withCode:(NSString *)messageCode
+ withMessage:(NSString *)message
+ withArgs:(va_list)args {
+ GULLogBasic(level, service, NO, messageCode, message, args);
+}
+
+@end
diff --git a/GoogleUtilities/Logger/Private/GULLogger.h b/GoogleUtilities/Logger/Private/GULLogger.h
new file mode 100644
index 0000000..c8b12e8
--- /dev/null
+++ b/GoogleUtilities/Logger/Private/GULLogger.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import <GoogleUtilities/GULLoggerLevel.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * The services used in the logger.
+ */
+typedef NSString *const GULLoggerService;
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/**
+ * Initialize GULLogger.
+ * (required) overrideSTDERR Override the aslOptions to ASL_OPT_STDERR.
+ * (required) forceDebugMode Force the asl level to ASL_LEVEL_DEBUG.
+ */
+extern void GULLoggerInitializeASL(BOOL overrideSTDERR, BOOL forceDebugMode);
+
+/**
+ * Changes the default logging level of GULLoggerLevelNotice to a user-specified level.
+ * The default level cannot be set above GULLoggerLevelNotice if the app is running from App Store.
+ * (required) log level (one of the GULLoggerLevel enum values).
+ */
+extern void GULSetLoggerLevel(GULLoggerLevel loggerLevel);
+
+/**
+ * Checks if the specified logger level is loggable given the current settings.
+ * (required) log level (one of the GULLoggerLevel enum values).
+ */
+extern BOOL GULIsLoggableLevel(GULLoggerLevel loggerLevel);
+
+/**
+ * Register version to include in logs.
+ * (required) version
+ */
+extern void GULLoggerRegisterVersion(const char *version);
+
+/**
+ * Logs a message to the Xcode console and the device log. If running from AppStore, will
+ * not log any messages with a level higher than GULLoggerLevelNotice to avoid log spamming.
+ * (required) log level (one of the GULLoggerLevel enum values).
+ * (required) service name of type GULLoggerService.
+ * (required) message code starting with "I-" which means iOS, followed by a capitalized
+ * three-character service identifier and a six digit integer message ID that is unique
+ * within the service.
+ * An example of the message code is @"I-COR000001".
+ * (required) message string which can be a format string.
+ * (optional) variable arguments list obtained from calling va_start, used when message is a format
+ * string.
+ */
+extern void GULLogBasic(GULLoggerLevel level,
+ GULLoggerService service,
+ BOOL forceLog,
+ NSString *messageCode,
+ NSString *message,
+// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable
+// See: http://stackoverflow.com/q/29095469
+#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX
+ va_list args_ptr
+#else
+ va_list _Nullable args_ptr
+#endif
+);
+
+/**
+ * The following functions accept the following parameters in order:
+ * (required) service name of type GULLoggerService.
+ * (required) message code starting from "I-" which means iOS, followed by a capitalized
+ * three-character service identifier and a six digit integer message ID that is unique
+ * within the service.
+ * An example of the message code is @"I-COR000001".
+ * See go/firebase-log-proposal for details.
+ * (required) message string which can be a format string.
+ * (optional) the list of arguments to substitute into the format string.
+ * Example usage:
+ * GULLogError(kGULLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name);
+ */
+extern void GULLogError(GULLoggerService service,
+ BOOL force,
+ NSString *messageCode,
+ NSString *message,
+ ...) NS_FORMAT_FUNCTION(4, 5);
+extern void GULLogWarning(GULLoggerService service,
+ BOOL force,
+ NSString *messageCode,
+ NSString *message,
+ ...) NS_FORMAT_FUNCTION(4, 5);
+extern void GULLogNotice(GULLoggerService service,
+ BOOL force,
+ NSString *messageCode,
+ NSString *message,
+ ...) NS_FORMAT_FUNCTION(4, 5);
+extern void GULLogInfo(GULLoggerService service,
+ BOOL force,
+ NSString *messageCode,
+ NSString *message,
+ ...) NS_FORMAT_FUNCTION(4, 5);
+extern void GULLogDebug(GULLoggerService service,
+ BOOL force,
+ NSString *messageCode,
+ NSString *message,
+ ...) NS_FORMAT_FUNCTION(4, 5);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
+
+@interface GULLoggerWrapper : NSObject
+
+/**
+ * Objective-C wrapper for GULLogBasic to allow weak linking to GULLogger
+ * (required) log level (one of the GULLoggerLevel enum values).
+ * (required) service name of type GULLoggerService.
+ * (required) message code starting with "I-" which means iOS, followed by a capitalized
+ * three-character service identifier and a six digit integer message ID that is unique
+ * within the service.
+ * An example of the message code is @"I-COR000001".
+ * (required) message string which can be a format string.
+ * (optional) variable arguments list obtained from calling va_start, used when message is a format
+ * string.
+ */
+
++ (void)logWithLevel:(GULLoggerLevel)level
+ withService:(GULLoggerService)service
+ withCode:(NSString *)messageCode
+ withMessage:(NSString *)message
+ withArgs:(va_list)args;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/GoogleUtilities/Logger/Public/GULLoggerLevel.h b/GoogleUtilities/Logger/Public/GULLoggerLevel.h
new file mode 100644
index 0000000..81ff212
--- /dev/null
+++ b/GoogleUtilities/Logger/Public/GULLoggerLevel.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * The log levels used by internal logging.
+ */
+typedef NS_ENUM(NSInteger, GULLoggerLevel) {
+ /** Error level, matches ASL_LEVEL_ERR. */
+ GULLoggerLevelError = 3,
+ /** Warning level, matches ASL_LEVEL_WARNING. */
+ GULLoggerLevelWarning = 4,
+ /** Notice level, matches ASL_LEVEL_NOTICE. */
+ GULLoggerLevelNotice = 5,
+ /** Info level, matches ASL_LEVEL_INFO. */
+ GULLoggerLevelInfo = 6,
+ /** Debug level, matches ASL_LEVEL_DEBUG. */
+ GULLoggerLevelDebug = 7,
+ /** Minimum log level. */
+ GULLoggerLevelMin = GULLoggerLevelError,
+ /** Maximum log level. */
+ GULLoggerLevelMax = GULLoggerLevelDebug
+} NS_SWIFT_NAME(GoogleLoggerLevel);