FIRMessagingLogger.m 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "FIRMessagingLogger.h"
  17. #import "FIRLogger.h"
  18. #import "FIRMessagingFileLogger.h"
  19. /**
  20. * A log formatter that prefixes log messages with "FIRMessaging".
  21. */
  22. @interface FIRMessagingLogStandardFormatter : NSObject<FIRMessagingLogFormatter>
  23. @property(nonatomic, readwrite, strong) NSDateFormatter *dateFormatter;
  24. @end
  25. @implementation FIRMessagingLogStandardFormatter
  26. static NSString *const kFIRMessagingLogPrefix = @"FIRMessaging";
  27. - (id)init {
  28. if ((self = [super init])) {
  29. _dateFormatter = [[NSDateFormatter alloc] init];
  30. [_dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
  31. [_dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"];
  32. }
  33. return self;
  34. }
  35. /**
  36. * Returns a formatted string prefixed with "FIRMessaging" to allow
  37. * FIRMessaging output to be easily differentiated in logs.
  38. *
  39. * @param func the name of the function calling the logger
  40. * @param fmt the format string
  41. * @param args the list of arguments for the format string
  42. * @param level the logging level (eg. debug, info)
  43. * @return the formatted string prefixed with "FIRMessaging".
  44. */
  45. - (NSString *)stringForFunc:(NSString *)func
  46. withFormat:(NSString *)fmt
  47. valist:(va_list)args
  48. level:(FIRMessagingLogLevel)level NS_FORMAT_FUNCTION(2, 0) {
  49. if (!(fmt && args)) {
  50. return nil;
  51. }
  52. NSString *logMessage = [[NSString alloc] initWithFormat:fmt arguments:args];
  53. NSString *logLevelString = [self stringForLogLevel:level];
  54. NSString *dateString = [self.dateFormatter stringFromDate:[NSDate date]];
  55. return [NSString stringWithFormat:@"%@: <%@/%@> %@",
  56. dateString, kFIRMessagingLogPrefix, logLevelString, logMessage];
  57. }
  58. - (NSString *)stringForLogLevel:(FIRMessagingLogLevel)level {
  59. switch (level) {
  60. case kFIRMessagingLogLevelDebug:
  61. return @"DEBUG";
  62. case kFIRMessagingLogLevelInfo:
  63. return @"INFO";
  64. case kFIRMessagingLogLevelError:
  65. return @"WARNING";
  66. case kFIRMessagingLogLevelAssert:
  67. return @"ERROR";
  68. default:
  69. return @"INFO";
  70. }
  71. }
  72. @end
  73. @interface FIRMessagingLogLevelFilter ()
  74. @property(nonatomic, readwrite, assign) FIRMessagingLogLevel level;
  75. @end
  76. @implementation FIRMessagingLogLevelFilter
  77. - (instancetype)initWithLevel:(FIRMessagingLogLevel)level {
  78. self = [super init];
  79. if (self) {
  80. _level = level;
  81. }
  82. return self;
  83. }
  84. - (BOOL)filterAllowsMessage:(NSString *)msg level:(FIRMessagingLogLevel)level {
  85. #if defined(DEBUG) && DEBUG
  86. return YES;
  87. #endif
  88. BOOL allow = YES;
  89. switch (level) {
  90. case kFIRMessagingLogLevelDebug:
  91. allow = NO;
  92. break;
  93. case kFIRMessagingLogLevelInfo:
  94. case kFIRMessagingLogLevelError:
  95. case kFIRMessagingLogLevelAssert:
  96. allow = (level >= self.level);
  97. break;
  98. default:
  99. allow = NO;
  100. break;
  101. }
  102. return allow;
  103. }
  104. @end
  105. // Copied from FIRMessagingLogger. Standard implementation to write logs to console.
  106. @interface NSFileHandle (FIRMessagingFileHandleLogWriter) <FIRMessagingLogWriter>
  107. @end
  108. @implementation NSFileHandle (FIRMessagingFileHandleLogWriter)
  109. - (void)logMessage:(NSString *)msg level:(FIRMessagingLogLevel)level {
  110. @synchronized(self) {
  111. // Closed pipes should not generate exceptions in our caller. Catch here
  112. // as well [FIRMessagingLogger logInternalFunc:...] so that an exception in this
  113. // writer does not prevent other writers from having a chance.
  114. @try {
  115. NSString *line = [NSString stringWithFormat:@"%@\n", msg];
  116. [self writeData:[line dataUsingEncoding:NSUTF8StringEncoding]];
  117. }
  118. @catch (id e) {
  119. // Ignored
  120. }
  121. }
  122. }
  123. @end
  124. @interface FIRMessagingLogger ()
  125. @end
  126. @implementation FIRMessagingLogger
  127. + (instancetype)standardLogger {
  128. id<FIRMessagingLogWriter> writer;
  129. id<FIRMessagingLogFormatter> formatter;
  130. id<FIRMessagingLogFilter> filter;
  131. #if FIRMessaging_PROBER
  132. writer = [[FIRMessagingFileLogWriter alloc] init];
  133. formatter = [[FIRMessagingFileLogFormatter alloc] init];
  134. filter = [[FIRMessagingFileLogFilter alloc] init];
  135. #else
  136. writer = [NSFileHandle fileHandleWithStandardOutput];
  137. formatter = [[FIRMessagingLogStandardFormatter alloc] init];
  138. filter = [[FIRMessagingLogLevelFilter alloc] init];
  139. #endif
  140. return [[FIRMessagingLogger alloc] initWithFilter:filter formatter:formatter writer:writer];
  141. }
  142. - (instancetype)initWithFilter:(id<FIRMessagingLogFilter>)filter
  143. formatter:(id<FIRMessagingLogFormatter>)formatter
  144. writer:(id<FIRMessagingLogWriter>)writer {
  145. self = [super init];
  146. if (self) {
  147. _filter = filter;
  148. _formatter = formatter;
  149. _writer = writer;
  150. }
  151. return self;
  152. }
  153. #pragma mark - Log Helpers
  154. + (NSString *)formatMessageCode:(FIRMessagingMessageCode)messageCode {
  155. return [NSString stringWithFormat:@"I-FCM%06ld", (long)messageCode];
  156. }
  157. - (void)logFuncDebug:(const char *)func
  158. messageCode:(FIRMessagingMessageCode)messageCode
  159. msg:(NSString *)fmt, ... {
  160. va_list args;
  161. va_start(args, fmt);
  162. FIRLogBasic(FIRLoggerLevelDebug, kFIRLoggerMessaging,
  163. [FIRMessagingLogger formatMessageCode:messageCode], fmt, args);
  164. va_end(args);
  165. #if FIRMessaging_PROBER
  166. va_start(args, fmt);
  167. [self logInternalFunc:func format:fmt valist:args level:kFIRMessagingLogLevelDebug];
  168. va_end(args);
  169. #endif
  170. }
  171. - (void)logFuncInfo:(const char *)func
  172. messageCode:(FIRMessagingMessageCode)messageCode
  173. msg:(NSString *)fmt, ... {
  174. va_list args;
  175. va_start(args, fmt);
  176. FIRLogBasic(FIRLoggerLevelInfo, kFIRLoggerMessaging,
  177. [FIRMessagingLogger formatMessageCode:messageCode], fmt, args);
  178. va_end(args);
  179. #if FIRMessaging_PROBER
  180. va_start(args, fmt);
  181. [self logInternalFunc:func format:fmt valist:args level:kFIRMessagingLogLevelInfo];
  182. va_end(args);
  183. #endif
  184. }
  185. - (void)logFuncNotice:(const char *)func
  186. messageCode:(FIRMessagingMessageCode)messageCode
  187. msg:(NSString *)fmt, ... {
  188. va_list args;
  189. va_start(args, fmt);
  190. FIRLogBasic(FIRLoggerLevelNotice, kFIRLoggerMessaging,
  191. [FIRMessagingLogger formatMessageCode:messageCode], fmt, args);
  192. va_end(args);
  193. #if FIRMessaging_PROBER
  194. va_start(args, fmt);
  195. // Treat FIRLoggerLevelNotice as "info" locally, since we don't have an equivalent
  196. [self logInternalFunc:func format:fmt valist:args level:kFIRMessagingLogLevelInfo];
  197. va_end(args);
  198. #endif
  199. }
  200. - (void)logFuncWarning:(const char *)func
  201. messageCode:(FIRMessagingMessageCode)messageCode
  202. msg:(NSString *)fmt, ... {
  203. va_list args;
  204. va_start(args, fmt);
  205. FIRLogBasic(FIRLoggerLevelWarning, kFIRLoggerMessaging,
  206. [FIRMessagingLogger formatMessageCode:messageCode], fmt, args);
  207. va_end(args);
  208. #if FIRMessaging_PROBER
  209. va_start(args, fmt);
  210. // Treat FIRLoggerLevelWarning as "error" locally, since we don't have an equivalent
  211. [self logInternalFunc:func format:fmt valist:args level:kFIRMessagingLogLevelError];
  212. va_end(args);
  213. #endif
  214. }
  215. - (void)logFuncError:(const char *)func
  216. messageCode:(FIRMessagingMessageCode)messageCode
  217. msg:(NSString *)fmt, ... {
  218. va_list args;
  219. va_start(args, fmt);
  220. FIRLogBasic(FIRLoggerLevelError, kFIRLoggerMessaging,
  221. [FIRMessagingLogger formatMessageCode:messageCode], fmt, args);
  222. va_end(args);
  223. #if FIRMessaging_PROBER
  224. va_start(args, fmt);
  225. [self logInternalFunc:func format:fmt valist:args level:kFIRMessagingLogLevelError];
  226. va_end(args);
  227. #endif
  228. }
  229. #pragma mark - Internal Helpers
  230. - (void)logInternalFunc:(const char *)func
  231. format:(NSString *)fmt
  232. valist:(va_list)args
  233. level:(FIRMessagingLogLevel)level {
  234. // Primary point where logging happens, logging should never throw, catch
  235. // everything.
  236. @try {
  237. NSString *fname = func ? [NSString stringWithUTF8String:func] : nil;
  238. NSString *msg = [self.formatter stringForFunc:fname
  239. withFormat:fmt
  240. valist:args
  241. level:level];
  242. if (msg && [self.filter filterAllowsMessage:msg level:level])
  243. [self.writer logMessage:msg level:level];
  244. }
  245. @catch (id e) {
  246. // Ignored
  247. }
  248. }
  249. @end
  250. FIRMessagingLogger *FIRMessagingSharedLogger() {
  251. static dispatch_once_t onceToken;
  252. static FIRMessagingLogger *logger;
  253. dispatch_once(&onceToken, ^{
  254. logger = [FIRMessagingLogger standardLogger];
  255. });
  256. return logger;
  257. }