added iOS source code
[wl-app.git] / iOS / Pods / GoogleUtilities / GoogleUtilities / Logger / GULLogger.m
1 // Copyright 2018 Google
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #import "Private/GULLogger.h"
16
17 #include <asl.h>
18
19 #import <GoogleUtilities/GULAppEnvironmentUtil.h>
20 #import "Public/GULLoggerLevel.h"
21
22 /// ASL client facility name used by GULLogger.
23 const char *kGULLoggerASLClientFacilityName = "com.google.utilities.logger";
24
25 static dispatch_once_t sGULLoggerOnceToken;
26
27 static aslclient sGULLoggerClient;
28
29 static dispatch_queue_t sGULClientQueue;
30
31 static BOOL sGULLoggerDebugMode;
32
33 static GULLoggerLevel sGULLoggerMaximumLevel;
34
35 // Allow clients to register a version to include in the log.
36 static const char *sVersion = "";
37
38 static GULLoggerService kGULLoggerLogger = @"[GULLogger]";
39
40 #ifdef DEBUG
41 /// The regex pattern for the message code.
42 static NSString *const kMessageCodePattern = @"^I-[A-Z]{3}[0-9]{6}$";
43 static NSRegularExpression *sMessageCodeRegex;
44 #endif
45
46 void GULLoggerInitializeASL(void) {
47   dispatch_once(&sGULLoggerOnceToken, ^{
48     NSInteger majorOSVersion = [[GULAppEnvironmentUtil systemVersion] integerValue];
49     uint32_t aslOptions = ASL_OPT_STDERR;
50 #if TARGET_OS_SIMULATOR
51     // The iOS 11 simulator doesn't need the ASL_OPT_STDERR flag.
52     if (majorOSVersion >= 11) {
53       aslOptions = 0;
54     }
55 #else
56     // Devices running iOS 10 or higher don't need the ASL_OPT_STDERR flag.
57     if (majorOSVersion >= 10) {
58       aslOptions = 0;
59     }
60 #endif  // TARGET_OS_SIMULATOR
61
62 #pragma clang diagnostic push
63 #pragma clang diagnostic ignored "-Wdeprecated-declarations"  // asl is deprecated
64     // Initialize the ASL client handle.
65     sGULLoggerClient = asl_open(NULL, kGULLoggerASLClientFacilityName, aslOptions);
66     sGULLoggerMaximumLevel = GULLoggerLevelNotice;
67
68     // Set the filter used by system/device log. Initialize in default mode.
69     asl_set_filter(sGULLoggerClient, ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE));
70
71     sGULClientQueue = dispatch_queue_create("GULLoggingClientQueue", DISPATCH_QUEUE_SERIAL);
72     dispatch_set_target_queue(sGULClientQueue,
73                               dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));
74 #ifdef DEBUG
75     sMessageCodeRegex =
76         [NSRegularExpression regularExpressionWithPattern:kMessageCodePattern options:0 error:NULL];
77 #endif
78   });
79 }
80
81 void GULLoggerEnableSTDERR(void) {
82   asl_add_log_file(sGULLoggerClient, STDERR_FILENO);
83 }
84
85 void GULLoggerForceDebug(void) {
86   // We should enable debug mode if we're not running from App Store.
87   if (![GULAppEnvironmentUtil isFromAppStore]) {
88     sGULLoggerDebugMode = YES;
89     GULSetLoggerLevel(GULLoggerLevelDebug);
90   }
91 }
92
93 void GULSetLoggerLevel(GULLoggerLevel loggerLevel) {
94   if (loggerLevel < GULLoggerLevelMin || loggerLevel > GULLoggerLevelMax) {
95     GULLogError(kGULLoggerLogger, NO, @"I-COR000023", @"Invalid logger level, %ld",
96                 (long)loggerLevel);
97     return;
98   }
99   GULLoggerInitializeASL();
100   // We should not raise the logger level if we are running from App Store.
101   if (loggerLevel >= GULLoggerLevelNotice && [GULAppEnvironmentUtil isFromAppStore]) {
102     return;
103   }
104
105   sGULLoggerMaximumLevel = loggerLevel;
106   dispatch_async(sGULClientQueue, ^{
107     asl_set_filter(sGULLoggerClient, ASL_FILTER_MASK_UPTO(loggerLevel));
108   });
109 }
110
111 /**
112  * Check if the level is high enough to be loggable.
113  */
114 __attribute__((no_sanitize("thread"))) BOOL GULIsLoggableLevel(GULLoggerLevel loggerLevel) {
115   GULLoggerInitializeASL();
116   if (sGULLoggerDebugMode) {
117     return YES;
118   }
119   return (BOOL)(loggerLevel <= sGULLoggerMaximumLevel);
120 }
121
122 #ifdef DEBUG
123 void GULResetLogger() {
124   sGULLoggerOnceToken = 0;
125 }
126
127 aslclient getGULLoggerClient() {
128   return sGULLoggerClient;
129 }
130
131 dispatch_queue_t getGULClientQueue() {
132   return sGULClientQueue;
133 }
134
135 BOOL getGULLoggerDebugMode() {
136   return sGULLoggerDebugMode;
137 }
138 #endif
139
140 void GULLoggerRegisterVersion(const char *version) {
141   sVersion = version;
142 }
143
144 void GULLogBasic(GULLoggerLevel level,
145                  GULLoggerService service,
146                  BOOL forceLog,
147                  NSString *messageCode,
148                  NSString *message,
149                  va_list args_ptr) {
150   GULLoggerInitializeASL();
151   if (!(level <= sGULLoggerMaximumLevel || sGULLoggerDebugMode || forceLog)) {
152     return;
153   }
154
155 #ifdef DEBUG
156   NSCAssert(messageCode.length == 11, @"Incorrect message code length.");
157   NSRange messageCodeRange = NSMakeRange(0, messageCode.length);
158   NSUInteger numberOfMatches =
159       [sMessageCodeRegex numberOfMatchesInString:messageCode options:0 range:messageCodeRange];
160   NSCAssert(numberOfMatches == 1, @"Incorrect message code format.");
161 #endif
162   NSString *logMsg = [[NSString alloc] initWithFormat:message arguments:args_ptr];
163   logMsg = [NSString stringWithFormat:@"%s - %@[%@] %@", sVersion, service, messageCode, logMsg];
164   dispatch_async(sGULClientQueue, ^{
165     asl_log(sGULLoggerClient, NULL, level, "%s", logMsg.UTF8String);
166   });
167 }
168 #pragma clang diagnostic pop
169
170 /**
171  * Generates the logging functions using macros.
172  *
173  * Calling GULLogError(kGULLoggerCore, @"I-COR000001", @"Configure %@ failed.", @"blah") shows:
174  * yyyy-mm-dd hh:mm:ss.SSS sender[PID] <Error> [{service}][I-COR000001] Configure blah failed.
175  * Calling GULLogDebug(kGULLoggerCore, @"I-COR000001", @"Configure succeed.") shows:
176  * yyyy-mm-dd hh:mm:ss.SSS sender[PID] <Debug> [{service}][I-COR000001] Configure succeed.
177  */
178 #define GUL_LOGGING_FUNCTION(level)                                                     \
179   void GULLog##level(GULLoggerService service, BOOL force, NSString *messageCode,       \
180                      NSString *message, ...) {                                          \
181     va_list args_ptr;                                                                   \
182     va_start(args_ptr, message);                                                        \
183     GULLogBasic(GULLoggerLevel##level, service, force, messageCode, message, args_ptr); \
184     va_end(args_ptr);                                                                   \
185   }
186
187 GUL_LOGGING_FUNCTION(Error)
188 GUL_LOGGING_FUNCTION(Warning)
189 GUL_LOGGING_FUNCTION(Notice)
190 GUL_LOGGING_FUNCTION(Info)
191 GUL_LOGGING_FUNCTION(Debug)
192
193 #undef GUL_MAKE_LOGGER
194
195 #pragma mark - GULLoggerWrapper
196
197 @implementation GULLoggerWrapper
198
199 + (void)logWithLevel:(GULLoggerLevel)level
200          withService:(GULLoggerService)service
201             withCode:(NSString *)messageCode
202          withMessage:(NSString *)message
203             withArgs:(va_list)args {
204   GULLogBasic(level, service, NO, messageCode, message, args);
205 }
206
207 @end