diff --git a/GoogleDataLogger.podspec b/GoogleDataLogger.podspec index 1c0f58cec93..75df8a4899e 100644 --- a/GoogleDataLogger.podspec +++ b/GoogleDataLogger.podspec @@ -27,6 +27,8 @@ Shared library for iOS SDK data logging needs. s.source_files = 'GoogleDataLogger/GoogleDataLogger/**/*' s.public_header_files = 'GoogleDataLogger/GoogleDataLogger/Classes/Public/*.h' + s.dependency 'GoogleUtilities/Logger' + s.pod_target_xcconfig = { 'GCC_C_LANGUAGE_STANDARD' => 'c99' } diff --git a/GoogleDataLogger/GoogleDataLogger/Classes/GDLLogEvent.h b/GoogleDataLogger/GoogleDataLogger/Classes/GDLLogEvent.h index 64eee5411ca..8f5d0e81e2d 100644 --- a/GoogleDataLogger/GoogleDataLogger/Classes/GDLLogEvent.h +++ b/GoogleDataLogger/GoogleDataLogger/Classes/GDLLogEvent.h @@ -44,6 +44,9 @@ typedef NS_ENUM(NSInteger, GDLLogQoS) { /** The log map identifier, to allow backends to map the extension property to a proto. */ @property(readonly, nonatomic) NSString *logMapID; +/** The identifier for the backend this log will eventually be sent to. */ +@property(readonly, nonatomic) NSInteger logTarget; + /** The log object itself, encapsulated in the transport of your choice, as long as it implements * the GDLLogProto protocol. */ @property(nonatomic) id extension; @@ -60,9 +63,11 @@ typedef NS_ENUM(NSInteger, GDLLogQoS) { /** Initializes an instance using the given logMapID. * * @param logMapID The log map identifier. + * @param logTarget The log's target identifier. * @return An instance of this class. */ -- (instancetype)initWithLogMapID:(NSString *)logMapID NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithLogMapID:(NSString *)logMapID + logTarget:(NSInteger)logTarget NS_DESIGNATED_INITIALIZER; @end diff --git a/GoogleDataLogger/GoogleDataLogger/Classes/GDLLogEvent.m b/GoogleDataLogger/GoogleDataLogger/Classes/GDLLogEvent.m index 5d408e4c093..ae7ca6eb586 100644 --- a/GoogleDataLogger/GoogleDataLogger/Classes/GDLLogEvent.m +++ b/GoogleDataLogger/GoogleDataLogger/Classes/GDLLogEvent.m @@ -18,11 +18,13 @@ @implementation GDLLogEvent -- (instancetype)initWithLogMapID:(NSString *)logMapID { +- (instancetype)initWithLogMapID:(NSString *)logMapID logTarget:(NSInteger)logTarget { NSAssert(logMapID.length > 0, @"Please give a valid log map ID"); + NSAssert(logTarget > 0, @"A log target cannot be negative or 0"); self = [super init]; if (self) { _logMapID = logMapID; + _logTarget = logTarget; } return self; } diff --git a/GoogleDataLogger/GoogleDataLogger/Classes/GDLLogWriter.m b/GoogleDataLogger/GoogleDataLogger/Classes/GDLLogWriter.m index 208e1954fc8..71590b480e9 100644 --- a/GoogleDataLogger/GoogleDataLogger/Classes/GDLLogWriter.m +++ b/GoogleDataLogger/GoogleDataLogger/Classes/GDLLogWriter.m @@ -19,6 +19,7 @@ #import +#import "GDLConsoleLogger.h" #import "GDLLogStorage.h" @implementation GDLLogWriter @@ -48,8 +49,14 @@ - (void)writeLog:(GDLLogEvent *)log dispatch_async(_logWritingQueue, ^{ GDLLogEvent *transformedLog = log; for (id transformer in logTransformers) { - transformedLog = [transformer transform:transformedLog]; - if (!transformedLog) { + if ([transformer respondsToSelector:@selector(transform:)]) { + transformedLog = [transformer transform:transformedLog]; + if (!transformedLog) { + return; + } + } else { + GDLLogWarning(GDLMCWTransformerDoesntImplementTransform, + @"Transformer doesn't implement transform: %@", transformer); return; } } diff --git a/GoogleDataLogger/GoogleDataLogger/Classes/GDLLogger.m b/GoogleDataLogger/GoogleDataLogger/Classes/GDLLogger.m index f5176ed54bf..d0f1f8a6839 100644 --- a/GoogleDataLogger/GoogleDataLogger/Classes/GDLLogger.m +++ b/GoogleDataLogger/GoogleDataLogger/Classes/GDLLogger.m @@ -17,6 +17,7 @@ #import "GDLLogger.h" #import "GDLLogEvent.h" +#import "GDLLogWriter.h" @interface GDLLogger () @@ -49,18 +50,16 @@ - (instancetype)initWithLogMapID:(NSString *)logMapID - (void)logTelemetryEvent:(GDLLogEvent *)logEvent { NSAssert(logEvent, @"You can't log a nil event"); - - // TODO(mikehaney24): Implement. + [[GDLLogWriter sharedInstance] writeLog:logEvent afterApplyingTransformers:_logTransformers]; } - (void)logDataEvent:(GDLLogEvent *)logEvent { NSAssert(logEvent, @"You can't log a nil event"); - - // TODO(mikehaney24): Implement. + [[GDLLogWriter sharedInstance] writeLog:logEvent afterApplyingTransformers:_logTransformers]; } - (GDLLogEvent *)newEvent { - return [[GDLLogEvent alloc] initWithLogMapID:_logMapID]; + return [[GDLLogEvent alloc] initWithLogMapID:_logMapID logTarget:_logTarget]; } @end diff --git a/GoogleDataLogger/GoogleDataLogger/Classes/Public/GDLLogTransformer.h b/GoogleDataLogger/GoogleDataLogger/Classes/Public/GDLLogTransformer.h index 5bba84d0f30..c8e072e8d0e 100644 --- a/GoogleDataLogger/GoogleDataLogger/Classes/Public/GDLLogTransformer.h +++ b/GoogleDataLogger/GoogleDataLogger/Classes/Public/GDLLogTransformer.h @@ -19,7 +19,9 @@ @class GDLLogEvent; /** Defines the API that log transformers must adopt. */ -@protocol GDLLogTransformer +@protocol GDLLogTransformer + +@required /** Transforms a log by applying some logic to it. Logs returned can be nil, for example, in * instances where the log should be sampled. diff --git a/GoogleDataLogger/GoogleDataLogger/DependencyWrappers/GDLConsoleLogger.h b/GoogleDataLogger/GoogleDataLogger/DependencyWrappers/GDLConsoleLogger.h new file mode 100644 index 00000000000..aaaa23c6edd --- /dev/null +++ b/GoogleDataLogger/GoogleDataLogger/DependencyWrappers/GDLConsoleLogger.h @@ -0,0 +1,48 @@ +/* + * 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 "GULLogger.h" + +/** The console logger prefix. */ +static GULLoggerService kGDLConsoleLogger = @"[GoogleDataLogger]"; + +/** A list of message codes to print in the logger that help to correspond printed messages with + * code locations. + * + * Prefixes: + * - MCW => MessageCodeWarning + */ +typedef NS_ENUM(NSInteger, GDLMessageCode) { + + /** For warning messages concerning transform: not being implemented by a log transformer. */ + GDLMCWTransformerDoesntImplementTransform = 1 +}; + +/** */ +FOUNDATION_EXTERN NSString *GDLMessageCodeEnumToString(GDLMessageCode code); + +/** Logs the warningMessage string to the console at the warning level. + * + * @param warningMessageFormat The format string to log to the console. + */ +FOUNDATION_EXTERN void GDLLogWarning(GDLMessageCode messageCode, + NSString *warningMessageFormat, + ...) NS_FORMAT_FUNCTION(2, 3); + +// A define to wrap GULLogWarning with slightly more convenient usage. +#define GDLLogWarning(MESSAGE_CODE, MESSAGE_FORMAT, ...) \ + GULLogWarning(kGDLConsoleLogger, YES, GDLMessageCodeEnumToString(MESSAGE_CODE), MESSAGE_FORMAT, \ + __VA_ARGS__); diff --git a/GoogleDataLogger/GoogleDataLogger/DependencyWrappers/GDLConsoleLogger.m b/GoogleDataLogger/GoogleDataLogger/DependencyWrappers/GDLConsoleLogger.m new file mode 100644 index 00000000000..a12676e5a3b --- /dev/null +++ b/GoogleDataLogger/GoogleDataLogger/DependencyWrappers/GDLConsoleLogger.m @@ -0,0 +1,21 @@ +/* + * 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 "GDLConsoleLogger.h" + +NSString* GDLMessageCodeEnumToString(GDLMessageCode code) { + return [[NSString alloc] initWithFormat:@"I-GDL%06ld", (long)code]; +} diff --git a/GoogleDataLogger/Tests/GDLLogEventTest.m b/GoogleDataLogger/Tests/GDLLogEventTest.m index 131dd61c515..c96c00907ee 100644 --- a/GoogleDataLogger/Tests/GDLLogEventTest.m +++ b/GoogleDataLogger/Tests/GDLLogEventTest.m @@ -25,8 +25,8 @@ @interface GDLLogEventTest : XCTestCase @implementation GDLLogEventTest - (void)testInit { - XCTAssertNotNil([[GDLLogEvent alloc] initWithLogMapID:@"1"]); - XCTAssertThrows([[GDLLogEvent alloc] initWithLogMapID:@""]); + XCTAssertNotNil([[GDLLogEvent alloc] initWithLogMapID:@"1" logTarget:1]); + XCTAssertThrows([[GDLLogEvent alloc] initWithLogMapID:@"" logTarget:1]); } @end diff --git a/GoogleDataLogger/Tests/GDLLogWriterTest.m b/GoogleDataLogger/Tests/GDLLogWriterTest.m index ee902f872d7..d7e88416915 100644 --- a/GoogleDataLogger/Tests/GDLLogWriterTest.m +++ b/GoogleDataLogger/Tests/GDLLogWriterTest.m @@ -34,6 +34,18 @@ - (GDLLogEvent *)transform:(GDLLogEvent *)logEvent { @end +@interface GDLLogWriterTestNewLogTransformer : NSObject + +@end + +@implementation GDLLogWriterTestNewLogTransformer + +- (GDLLogEvent *)transform:(GDLLogEvent *)logEvent { + return [[GDLLogEvent alloc] initWithLogMapID:@"new" logTarget:1]; +} + +@end + @interface GDLLogWriterTest : XCTestCase @end @@ -50,18 +62,20 @@ - (void)testSharedInstance { XCTAssertEqual([GDLLogWriter sharedInstance], [GDLLogWriter sharedInstance]); } +/** Tests writing a log without a transformer. */ - (void)testWriteLogWithoutTransformers { GDLLogWriter *writer = [GDLLogWriter sharedInstance]; - GDLLogEvent *log = [[GDLLogEvent alloc] initWithLogMapID:@"1"]; + GDLLogEvent *log = [[GDLLogEvent alloc] initWithLogMapID:@"1" logTarget:1]; XCTAssertNoThrow([writer writeLog:log afterApplyingTransformers:nil]); dispatch_sync(writer.logWritingQueue, ^{ // TODO(mikehaney24): Assert that storage contains the log. }); } +/** Tests writing a log with a transformer that nils out the log. */ - (void)testWriteLogWithTransformersThatNilTheLog { GDLLogWriter *writer = [GDLLogWriter sharedInstance]; - GDLLogEvent *log = [[GDLLogEvent alloc] initWithLogMapID:@"2"]; + GDLLogEvent *log = [[GDLLogEvent alloc] initWithLogMapID:@"2" logTarget:1]; NSArray> *transformers = @[ [[GDLLogWriterTestNilingTransformer alloc] init] ]; XCTAssertNoThrow([writer writeLog:log afterApplyingTransformers:transformers]); @@ -70,4 +84,31 @@ - (void)testWriteLogWithTransformersThatNilTheLog { }); } +/** Tests writing a log with a transformer that creates a new log. */ +- (void)testWriteLogWithTransformersThatCreateANewLog { + GDLLogWriter *writer = [GDLLogWriter sharedInstance]; + GDLLogEvent *log = [[GDLLogEvent alloc] initWithLogMapID:@"2" logTarget:1]; + NSArray> *transformers = + @[ [[GDLLogWriterTestNewLogTransformer alloc] init] ]; + XCTAssertNoThrow([writer writeLog:log afterApplyingTransformers:transformers]); + dispatch_sync(writer.logWritingQueue, ^{ + // TODO(mikehaney24): Assert that storage contains the new log. + }); +} + +/** Tests that using a transformer without transform: implemented throws. */ +- (void)testWriteLogWithBadTransformer { + GDLLogWriter *writer = [GDLLogWriter sharedInstance]; + GDLLogEvent *log = [[GDLLogEvent alloc] initWithLogMapID:@"2" logTarget:1]; + NSArray *transformers = @[ [[NSObject alloc] init] ]; + @try { + dispatch_sync(writer.logWritingQueue, ^{ + // TODO(mikehaney24): Assert that storage contains the new log. + [writer writeLog:log afterApplyingTransformers:transformers]; + }); + } @catch (NSException *exception) { + NSLog(@""); + } +} + @end