Skip to content

Commit ea80142

Browse files
authored
Implement NSSecureCoding protocol for GDLLogEvent (#2191)
* Implement NSSecureCodingProtocol for GDLLogEvent * Style changes. * Refactor to address some comments and structure GDLLogEvent and GDLLogProto are moved to the public folder. GDLLogEvent has had some public API moved to a private header. GDLLogWriter now writes the extension object to data after transforming, for serialization purposes. Various headers updated to conform to module header rules.
1 parent fe53dd3 commit ea80142

13 files changed

+222
-16
lines changed

GoogleDataLogger/GoogleDataLogger/Classes/GDLLogEvent.m

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
* limitations under the License.
1515
*/
1616

17-
#import "GDLLogEvent.h"
17+
#import <GoogleDataLogger/GDLLogEvent.h>
18+
19+
#import "GDLLogEvent_Private.h"
1820

1921
@implementation GDLLogEvent
2022

@@ -29,4 +31,56 @@ - (instancetype)initWithLogMapID:(NSString *)logMapID logTarget:(NSInteger)logTa
2931
return self;
3032
}
3133

34+
#pragma mark - NSSecureCoding and NSCoding Protocols
35+
36+
/** NSCoding key for logMapID property. */
37+
static NSString *logMapIDKey = @"_logMapID";
38+
39+
/** NSCoding key for logTarget property. */
40+
static NSString *logTargetKey = @"_logTarget";
41+
42+
/** NSCoding key for extensionBytes property. */
43+
static NSString *extensionBytesKey = @"_extensionBytes";
44+
45+
/** NSCoding key for qosTier property. */
46+
static NSString *qosTierKey = @"_qosTier";
47+
48+
/** NSCoding key for clockSnapshot.timeMillis property. */
49+
static NSString *clockSnapshotTimeMillisKey = @"_clockSnapshotTimeMillis";
50+
51+
/** NSCoding key for clockSnapshot.uptimeMillis property. */
52+
static NSString *clockSnapshotUpTimeMillis = @"_clockSnapshotUpTimeMillis";
53+
54+
/** NSCoding key for clockSnapshot.timezoneOffsetMillis property. */
55+
static NSString *clockSnapshotTimezoneOffsetMillis = @"_clockSnapshotTimezoneOffsetMillis";
56+
57+
+ (BOOL)supportsSecureCoding {
58+
return YES;
59+
}
60+
61+
- (id)initWithCoder:(NSCoder *)aDecoder {
62+
NSString *logMapID = [aDecoder decodeObjectOfClass:[NSObject class] forKey:logMapIDKey];
63+
NSInteger logTarget = [aDecoder decodeIntegerForKey:logTargetKey];
64+
self = [self initWithLogMapID:logMapID logTarget:logTarget];
65+
if (self) {
66+
_extensionBytes = [aDecoder decodeObjectOfClass:[NSData class] forKey:extensionBytesKey];
67+
_qosTier = [aDecoder decodeIntegerForKey:qosTierKey];
68+
_clockSnapshot.timeMillis = [aDecoder decodeInt64ForKey:clockSnapshotTimeMillisKey];
69+
_clockSnapshot.uptimeMillis = [aDecoder decodeInt64ForKey:clockSnapshotUpTimeMillis];
70+
_clockSnapshot.timezoneOffsetMillis =
71+
[aDecoder decodeInt64ForKey:clockSnapshotTimezoneOffsetMillis];
72+
}
73+
return self;
74+
}
75+
76+
- (void)encodeWithCoder:(NSCoder *)aCoder {
77+
[aCoder encodeObject:_logMapID forKey:logMapIDKey];
78+
[aCoder encodeInteger:_logTarget forKey:logTargetKey];
79+
[aCoder encodeObject:_extensionBytes forKey:extensionBytesKey];
80+
[aCoder encodeInteger:_qosTier forKey:qosTierKey];
81+
[aCoder encodeInt64:_clockSnapshot.timeMillis forKey:clockSnapshotTimeMillisKey];
82+
[aCoder encodeInt64:_clockSnapshot.uptimeMillis forKey:clockSnapshotUpTimeMillis];
83+
[aCoder encodeInt64:_clockSnapshot.timezoneOffsetMillis forKey:clockSnapshotTimezoneOffsetMillis];
84+
}
85+
3286
@end

GoogleDataLogger/GoogleDataLogger/Classes/GDLLogWriter.m

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#import <GoogleDataLogger/GDLLogTransformer.h>
2121

2222
#import "GDLConsoleLogger.h"
23+
#import "GDLLogEvent_Private.h"
2324
#import "GDLLogStorage.h"
2425

2526
@implementation GDLLogWriter
@@ -60,6 +61,17 @@ - (void)writeLog:(GDLLogEvent *)log
6061
return;
6162
}
6263
}
64+
65+
// Convert the extension to bytes after transforming.
66+
NSAssert([log.extension respondsToSelector:@selector(protoBytes)],
67+
@"The log event's extension must respond to -protoBytes.");
68+
if ([log.extension respondsToSelector:@selector(protoBytes)]) {
69+
log.extensionBytes = [log.extension protoBytes];
70+
log.extension = nil;
71+
} else {
72+
GDLLogWarning(GDLMCWExtensionMissingBytesImpl, @"%@",
73+
@"The log event's extension must respond to -protoBytes.");
74+
}
6375
// TODO(mikehaney24): [[GDLLogStorage sharedInstance] storeLog:transformedLog];
6476
});
6577
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2018 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+
17+
#import "GDLLogEvent.h"
18+
19+
#import "GDLLogClock.h"
20+
21+
NS_ASSUME_NONNULL_BEGIN
22+
23+
@interface GDLLogEvent ()
24+
25+
/** The serialized bytes of the log object. */
26+
@property(nonatomic) NSData *extensionBytes;
27+
28+
/** The quality of service tier this log belongs to. */
29+
@property(nonatomic) GDLLogQoS qosTier;
30+
31+
/** The clock snapshot at the time of logging. */
32+
@property(nonatomic) GDLLogClockSnapshot clockSnapshot;
33+
34+
@end
35+
36+
NS_ASSUME_NONNULL_END

GoogleDataLogger/GoogleDataLogger/Classes/GDLLogEvent.h renamed to GoogleDataLogger/GoogleDataLogger/Classes/Public/GDLLogEvent.h

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
#import <Foundation/Foundation.h>
1818

19-
#import "GDLLogClock.h"
2019
#import "GDLLogProto.h"
2120

2221
NS_ASSUME_NONNULL_BEGIN
@@ -39,7 +38,7 @@ typedef NS_ENUM(NSInteger, GDLLogQoS) {
3938
GDLLogQoSFast = 4
4039
};
4140

42-
@interface GDLLogEvent : NSObject
41+
@interface GDLLogEvent : NSObject <NSSecureCoding>
4342

4443
/** The log map identifier, to allow backends to map the extension property to a proto. */
4544
@property(readonly, nonatomic) NSString *logMapID;
@@ -49,13 +48,7 @@ typedef NS_ENUM(NSInteger, GDLLogQoS) {
4948

5049
/** The log object itself, encapsulated in the transport of your choice, as long as it implements
5150
* the GDLLogProto protocol. */
52-
@property(nonatomic) id<GDLLogProto> extension;
53-
54-
/** The quality of service tier this log belongs to. */
55-
@property(nonatomic) GDLLogQoS qosTier;
56-
57-
/** The clock snapshot at the time of logging. */
58-
@property(nonatomic) GDLLogClockSnapshot clockSnapshot;
51+
@property(nullable, nonatomic) id<GDLLogProto> extension;
5952

6053
// Please use the designated initializer.
6154
- (instancetype)init NS_UNAVAILABLE;

GoogleDataLogger/GoogleDataLogger/Classes/Public/GDLLogger.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,19 @@ NS_ASSUME_NONNULL_BEGIN
3838
logTransformers:(nullable NSArray<id<GDLLogTransformer>> *)logTransformers
3939
logTarget:(NSInteger)logTarget NS_DESIGNATED_INITIALIZER;
4040

41-
/** Logs an internal telemetry event. Logs sent using this API are lower in priority, and sometimes
42-
* won't be sent on their own.
41+
/** Copies and logs an internal telemetry event. Logs sent using this API are lower in priority, and
42+
* sometimes won't be sent on their own.
43+
*
44+
* @note This will convert the log event's extension proto to data and release the original log.
4345
*
4446
* @param logEvent The log event to log.
4547
*/
4648
- (void)logTelemetryEvent:(GDLLogEvent *)logEvent;
4749

48-
/** Logs an SDK service data event. Logs send using this API are higher in priority, and will cause
49-
* a network request at some point in the relative near future.
50+
/** Copies and logs an SDK service data event. Logs send using this API are higher in priority, and
51+
* will cause a network request at some point in the relative near future.
52+
*
53+
* @note This will convert the log event's extension proto to data and release the original log.
5054
*
5155
* @param logEvent The log event to log.
5256
*/

GoogleDataLogger/GoogleDataLogger/Classes/Public/GoogleDataLogger.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@
1414
* limitations under the License.
1515
*/
1616

17+
#import "GDLLogEvent.h"
18+
#import "GDLLogTransformer.h"
1719
#import "GDLLogger.h"

GoogleDataLogger/GoogleDataLogger/DependencyWrappers/GDLConsoleLogger.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ static GULLoggerService kGDLConsoleLogger = @"[GoogleDataLogger]";
2828
typedef NS_ENUM(NSInteger, GDLMessageCode) {
2929

3030
/** For warning messages concerning transform: not being implemented by a log transformer. */
31-
GDLMCWTransformerDoesntImplementTransform = 1
31+
GDLMCWTransformerDoesntImplementTransform = 1,
32+
33+
/** For warning messages concerning protoBytes: not being implemented by a log extension. */
34+
GDLMCWExtensionMissingBytesImpl = 2
3235
};
3336

3437
/** */

GoogleDataLogger/Tests/GDLLogEventTest.m

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,45 @@
1616

1717
#import <XCTest/XCTest.h>
1818

19-
#import "GDLLogEvent.h"
19+
#import <GoogleDataLogger/GDLLogEvent.h>
20+
21+
#import "GDLLogEvent_Private.h"
2022

2123
@interface GDLLogEventTest : XCTestCase
2224

2325
@end
2426

2527
@implementation GDLLogEventTest
2628

29+
/** Tests the designated initializer. */
2730
- (void)testInit {
2831
XCTAssertNotNil([[GDLLogEvent alloc] initWithLogMapID:@"1" logTarget:1]);
2932
XCTAssertThrows([[GDLLogEvent alloc] initWithLogMapID:@"" logTarget:1]);
3033
}
3134

35+
/** Tests NSKeyedArchiver encoding and decoding. */
36+
- (void)testArchiving {
37+
XCTAssertTrue([GDLLogEvent supportsSecureCoding]);
38+
GDLLogClockSnapshot clockSnapshot = {10, 100, 1000};
39+
GDLLogEvent *logEvent = [[GDLLogEvent alloc] initWithLogMapID:@"testID" logTarget:42];
40+
logEvent.extensionBytes = [@"someData" dataUsingEncoding:NSUTF8StringEncoding];
41+
logEvent.qosTier = GDLLogQoSTelemetry;
42+
logEvent.clockSnapshot = clockSnapshot;
43+
44+
NSData *archiveData = [NSKeyedArchiver archivedDataWithRootObject:logEvent];
45+
46+
// To ensure that all the objects being retained by the original logEvent are dealloc'd.
47+
logEvent = nil;
48+
49+
GDLLogEvent *decodedLogEvent = [NSKeyedUnarchiver unarchiveObjectWithData:archiveData];
50+
XCTAssertEqualObjects(decodedLogEvent.logMapID, @"testID");
51+
XCTAssertEqual(decodedLogEvent.logTarget, 42);
52+
XCTAssertEqualObjects(decodedLogEvent.extensionBytes,
53+
[@"someData" dataUsingEncoding:NSUTF8StringEncoding]);
54+
XCTAssertEqual(decodedLogEvent.qosTier, GDLLogQoSTelemetry);
55+
XCTAssertEqual(decodedLogEvent.clockSnapshot.timeMillis, 10);
56+
XCTAssertEqual(decodedLogEvent.clockSnapshot.uptimeMillis, 100);
57+
XCTAssertEqual(decodedLogEvent.clockSnapshot.timezoneOffsetMillis, 1000);
58+
}
59+
3260
@end

GoogleDataLogger/Tests/GDLLogWriterTest.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#import <GoogleDataLogger/GDLLogTransformer.h>
2020

2121
#import "GDLLogEvent.h"
22+
#import "GDLLogExtensionTesterClasses.h"
2223
#import "GDLLogWriter.h"
2324
#import "GDLLogWriter_Private.h"
2425

@@ -66,6 +67,7 @@ - (void)testSharedInstance {
6667
- (void)testWriteLogWithoutTransformers {
6768
GDLLogWriter *writer = [GDLLogWriter sharedInstance];
6869
GDLLogEvent *log = [[GDLLogEvent alloc] initWithLogMapID:@"1" logTarget:1];
70+
log.extension = [[GDLLogExtensionTesterSimple alloc] init];
6971
XCTAssertNoThrow([writer writeLog:log afterApplyingTransformers:nil]);
7072
dispatch_sync(writer.logWritingQueue, ^{
7173
// TODO(mikehaney24): Assert that storage contains the log.
@@ -76,6 +78,7 @@ - (void)testWriteLogWithoutTransformers {
7678
- (void)testWriteLogWithTransformersThatNilTheLog {
7779
GDLLogWriter *writer = [GDLLogWriter sharedInstance];
7880
GDLLogEvent *log = [[GDLLogEvent alloc] initWithLogMapID:@"2" logTarget:1];
81+
log.extension = [[GDLLogExtensionTesterSimple alloc] init];
7982
NSArray<id<GDLLogTransformer>> *transformers =
8083
@[ [[GDLLogWriterTestNilingTransformer alloc] init] ];
8184
XCTAssertNoThrow([writer writeLog:log afterApplyingTransformers:transformers]);
@@ -88,6 +91,7 @@ - (void)testWriteLogWithTransformersThatNilTheLog {
8891
- (void)testWriteLogWithTransformersThatCreateANewLog {
8992
GDLLogWriter *writer = [GDLLogWriter sharedInstance];
9093
GDLLogEvent *log = [[GDLLogEvent alloc] initWithLogMapID:@"2" logTarget:1];
94+
log.extension = [[GDLLogExtensionTesterSimple alloc] init];
9195
NSArray<id<GDLLogTransformer>> *transformers =
9296
@[ [[GDLLogWriterTestNewLogTransformer alloc] init] ];
9397
XCTAssertNoThrow([writer writeLog:log afterApplyingTransformers:transformers]);
@@ -100,6 +104,7 @@ - (void)testWriteLogWithTransformersThatCreateANewLog {
100104
- (void)testWriteLogWithBadTransformer {
101105
GDLLogWriter *writer = [GDLLogWriter sharedInstance];
102106
GDLLogEvent *log = [[GDLLogEvent alloc] initWithLogMapID:@"2" logTarget:1];
107+
log.extension = [[GDLLogExtensionTesterSimple alloc] init];
103108
NSArray *transformers = @[ [[NSObject alloc] init] ];
104109
@try {
105110
dispatch_sync(writer.logWritingQueue, ^{

GoogleDataLogger/Tests/GDLLoggerTest.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@
1616

1717
#import <XCTest/XCTest.h>
1818

19+
#import <GoogleDataLogger/GDLLogEvent.h>
1920
#import <GoogleDataLogger/GDLLogger.h>
2021

22+
#import "GDLLogExtensionTesterClasses.h"
23+
2124
@interface GDLLoggerTest : XCTestCase
2225

2326
@end
@@ -34,13 +37,15 @@ - (void)testInit {
3437
- (void)testLogTelemetryEvent {
3538
GDLLogger *logger = [[GDLLogger alloc] initWithLogMapID:@"1" logTransformers:nil logTarget:1];
3639
GDLLogEvent *event = [logger newEvent];
40+
event.extension = [[GDLLogExtensionTesterSimple alloc] init];
3741
XCTAssertNoThrow([logger logTelemetryEvent:event]);
3842
}
3943

4044
/** Tests logging a data event. */
4145
- (void)testLogDataEvent {
4246
GDLLogger *logger = [[GDLLogger alloc] initWithLogMapID:@"1" logTransformers:nil logTarget:1];
4347
GDLLogEvent *event = [logger newEvent];
48+
event.extension = [[GDLLogExtensionTesterSimple alloc] init];
4449
XCTAssertNoThrow([logger logDataEvent:event]);
4550
}
4651

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright 2018 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+
17+
#import <Foundation/Foundation.h>
18+
19+
#import <GoogleDataLogger/GDLLogProto.h>
20+
21+
NS_ASSUME_NONNULL_BEGIN
22+
23+
/** A class to represent a simple log proto. */
24+
@interface GDLLogExtensionTesterSimple : NSObject <GDLLogProto>
25+
26+
/** A string that will be turned into bytes. */
27+
@property(nonatomic) NSString *aString;
28+
29+
@end
30+
31+
NS_ASSUME_NONNULL_END
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2018 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+
17+
#import "GDLLogExtensionTesterClasses.h"
18+
19+
@implementation GDLLogExtensionTesterSimple
20+
21+
- (instancetype)init {
22+
self = [super init];
23+
if (self) {
24+
_aString = @"test";
25+
}
26+
return self;
27+
}
28+
29+
- (NSData *)protoBytes {
30+
return [_aString dataUsingEncoding:NSUTF8StringEncoding];
31+
}
32+
33+
@end

0 commit comments

Comments
 (0)