Skip to content

Lay the groundwork for CCT support, and include the prioritizer imple… #2602

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Mar 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,16 @@ jobs:
- ./scripts/if_changed.sh ./scripts/build.sh $PROJECT $PLATFORM
- ./scripts/if_changed.sh ./scripts/pod_lib_lint.sh GoogleDataTransport.podspec

# GoogleDataTransportCCTSupport unit tests and pod linting using the default Xcode version.
- stage: test
env:
- PROJECT=GoogleDataTransportCCTSupport PLATFORM=iOS METHOD=xcodebuild
before_install:
- ./scripts/if_changed.sh ./scripts/install_prereqs.sh
script:
- ./scripts/if_changed.sh ./scripts/build.sh $PROJECT $PLATFORM
- ./scripts/if_changed.sh ./scripts/pod_lib_lint.sh GoogleDataTransportCCTSupport.podspec

# Daily test for symbol collisions between Firebase and CocoaPods.
- stage: test
env:
Expand Down
2 changes: 1 addition & 1 deletion GoogleDataTransport/Tests/Unit/GDTUploadCoordinatorTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ - (void)testTimerIsRunningAtDesiredFrequency {
// It's expected that the timer called the prioritizer 10 times +/- 3 during that 1 second + the
// coordinator running before that.
dispatch_sync([GDTUploadCoordinator sharedInstance].coordinationQueue, ^{
XCTAssertEqualWithAccuracy(numberOfTimesCalled, 10, 3);
XCTAssertGreaterThan(numberOfTimesCalled, 4); // Some latency is expected on a busy system.
});
}

Expand Down
50 changes: 50 additions & 0 deletions GoogleDataTransportCCTSupport.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@

Pod::Spec.new do |s|
s.name = 'GoogleDataTransportCCTSupport'
s.version = '0.1.0'
s.summary = 'Support library for the GoogleDataTransport CCT log target.'


s.description = <<-DESC
Support library to provide event prioritization and uploading for the GoogleDataTransport CCT log target.
DESC

s.homepage = 'https://developers.google.com/'
s.license = { :type => 'Apache', :file => 'LICENSE' }
s.authors = 'Google, Inc.'
s.source = {
:git => 'https://github.com/firebase/firebase-ios-sdk.git',
:tag => 'GoogleDataLoggerCCTSupport-' + s.version.to_s
}

s.ios.deployment_target = '8.0'

s.cocoapods_version = '>= 1.6.0'

s.static_framework = true
s.prefix_header_file = false

s.source_files = 'GoogleDataTransportCCTSupport/GoogleDataTransportCCTSupport/Classes/**/*'
s.private_header_files = 'GoogleDataTransportCCTSupport/GoogleDataTransportCCTSupport/Classes/Private/*.h'

s.dependency 'GoogleDataTransport'
s.dependency 'nanopb'

s.pod_target_xcconfig = {
'GCC_C_LANGUAGE_STANDARD' => 'c99',
'GCC_TREAT_WARNINGS_AS_ERRORS' => 'YES',
'CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY' => 'YES',
'GCC_PREPROCESSOR_DEFINITIONS' =>
# The nanopb pod sets these defs, so we must too. (We *do* require 16bit
# (or larger) fields, so we'd have to set at least PB_FIELD_16BIT
# anyways.)
'PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1',
}

# Test specs
s.test_spec 'Tests-Unit' do |test_spec|
test_spec.requires_app_host = false
test_spec.source_files = 'GoogleDataTransportCCTSupport/Tests/Unit/**/*.{h,m}'
end

end
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*
* Copyright 2019 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 "GDTCCTPrioritizer.h"

const static NSUInteger kMillisPerDay = 8.64e+7;

@implementation GDTCCTPrioritizer

+ (void)load {
GDTCCTPrioritizer *prioritizer = [GDTCCTPrioritizer sharedInstance];
[[GDTRegistrar sharedInstance] registerPrioritizer:prioritizer target:kGDTTargetCCT];
}

/** Creates and returns the singleton instance of this class.
*
* @return The singleton instance of this class.
*/
+ (instancetype)sharedInstance {
static GDTCCTPrioritizer *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[GDTCCTPrioritizer alloc] init];
});
return sharedInstance;
}

- (instancetype)init {
self = [super init];
if (self) {
_queue = dispatch_queue_create("com.google.GDTCCTPrioritizer", DISPATCH_QUEUE_SERIAL);
_events = [[NSMutableSet alloc] init];
}
return self;
}

#pragma mark - GDTPrioritizer Protocol

- (void)prioritizeEvent:(GDTStoredEvent *)event {
dispatch_async(_queue, ^{
[self.events addObject:event];
});
}

- (void)unprioritizeEvents:(NSSet<GDTStoredEvent *> *)events {
dispatch_async(_queue, ^{
for (GDTStoredEvent *event in events) {
[self.events removeObject:event];
}
});
}

- (GDTUploadPackage *)uploadPackageWithConditions:(GDTUploadConditions)conditions {
GDTUploadPackage *package = [[GDTUploadPackage alloc] init];
dispatch_sync(_queue, ^{
NSSet<GDTStoredEvent *> *logEventsThatWillBeSent;
if ((conditions & GDTUploadConditionWifiData) == GDTUploadConditionWifiData) {
logEventsThatWillBeSent = [self logEventsOkToSendOnWifi];
} else {
logEventsThatWillBeSent = [self logEventsOkToSendOnMobileData];
}
if (self.timeOfLastDailyUpload) {
int64_t millisSinceLastUpload =
[GDTClock snapshot].timeMillis - self.timeOfLastDailyUpload.timeMillis;
if (millisSinceLastUpload > kMillisPerDay) {
logEventsThatWillBeSent =
[logEventsThatWillBeSent setByAddingObjectsFromSet:[self logEventsOkToSendDaily]];
}
} else {
self.timeOfLastDailyUpload = [GDTClock snapshot];
logEventsThatWillBeSent =
[logEventsThatWillBeSent setByAddingObjectsFromSet:[self logEventsOkToSendDaily]];
}
package.events = logEventsThatWillBeSent;
});
return package;
}

#pragma mark - Private helper methods

/** The different possible quality of service specifiers. High values indicate high priority. */
typedef NS_ENUM(NSInteger, GDTCCTQoSTier) {
/** The QoS tier wasn't set, and won't ever be sent. */
GDTCCTQoSDefault = 0,

/** This event is internal telemetry data that should not be sent on its own if possible. */
GDTCCTQoSTelemetry = 1,

/** This event should be sent, but in a batch only roughly once per day. */
GDTCCTQoSDaily = 2,

/** This event should only be uploaded on wifi. */
GDTCCTQoSWifiOnly = 5,
};

/** Converts a GDTEventQoS to a GDTCCTQoS tier.
*
* @param qosTier The GDTEventQoS value.
* @return A static NSNumber that represents the CCT QoS tier.
*/
FOUNDATION_STATIC_INLINE
NSNumber *GDTCCTQosTierFromGDTEventQosTier(GDTEventQoS qosTier) {
switch (qosTier) {
case GDTEventQoSTelemetry:
case GDTEventQoSWifiOnly:
return @(GDTCCTQoSWifiOnly);
break;

case GDTEventQoSDaily:
return @(GDTCCTQoSDaily);
break;

default:
return @(GDTCCTQoSDefault);
break;
}
}

/** Returns a set of logs that are ok to upload whilst on mobile data.
*
* @note This should be called from a thread safe method.
* @return A set of logs that are ok to upload whilst on mobile data.
*/
- (NSSet<GDTStoredEvent *> *)logEventsOkToSendOnMobileData {
return
[self.events objectsPassingTest:^BOOL(GDTStoredEvent *_Nonnull event, BOOL *_Nonnull stop) {
return [GDTCCTQosTierFromGDTEventQosTier(event.qosTier) isEqual:@(GDTCCTQoSDefault)];
}];
}

/** Returns a set of logs that are ok to upload whilst on wifi.
*
* @note This should be called from a thread safe method.
* @return A set of logs that are ok to upload whilst on wifi.
*/
- (NSSet<GDTStoredEvent *> *)logEventsOkToSendOnWifi {
return
[self.events objectsPassingTest:^BOOL(GDTStoredEvent *_Nonnull event, BOOL *_Nonnull stop) {
NSNumber *qosTier = GDTCCTQosTierFromGDTEventQosTier(event.qosTier);
return [qosTier isEqual:@(GDTCCTQoSDefault)] || [qosTier isEqual:@(GDTCCTQoSWifiOnly)];
}];
}

/** Returns a set of logs that only should have a single upload attempt per day.
*
* @note This should be called from a thread safe method.
* @return A set of logs that are ok to upload only once per day.
*/
- (NSSet<GDTStoredEvent *> *)logEventsOkToSendDaily {
return
[self.events objectsPassingTest:^BOOL(GDTStoredEvent *_Nonnull event, BOOL *_Nonnull stop) {
return [GDTCCTQosTierFromGDTEventQosTier(event.qosTier) isEqual:@(GDTCCTQoSDaily)];
}];
}

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2019 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 "GDTCCTUploader.h"

#import <GoogleDataTransport/GDTRegistrar.h>

@implementation GDTCCTUploader

+ (void)load {
GDTCCTUploader *uploader = [GDTCCTUploader sharedInstance];
[[GDTRegistrar sharedInstance] registerUploader:uploader target:kGDTTargetCCT];
}

+ (instancetype)sharedInstance {
static GDTCCTUploader *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[GDTCCTUploader alloc] init];
});
return sharedInstance;
}

- (void)uploadPackage:(nonnull GDTUploadPackage *)package
onComplete:(nonnull GDTUploaderCompletionBlock)onComplete {
}

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2019 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 <GoogleDataTransport/GoogleDataTransport.h>

/** Manages the prioritization of events from GoogleDataTransport. */
@interface GDTCCTPrioritizer : NSObject <GDTPrioritizer>

/** The queue on which this prioritizer operates. */
@property(nonatomic) dispatch_queue_t queue;

/** All log events that have been processed by this prioritizer. */
@property(nonatomic) NSMutableSet<GDTStoredEvent *> *events;

/** The most recent attempted upload of daily uploaded logs. */
@property(nonatomic) GDTClock *timeOfLastDailyUpload;

/** Creates and/or returns the singleton instance of the prioritizer. */
+ (instancetype)sharedInstance;

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2019 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 <GoogleDataTransport/GoogleDataTransport.h>

/** Class capable of uploading events to the CCT backend. */
@interface GDTCCTUploader : NSObject <GDTUploader>

/** Creates/returns the single instance. */
+ (instancetype)sharedInstance;

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
To build the protos:
- `brew intall protobuf`
- Download the latest stable release from https://github.com/nanopb/nanopb/releases
- `./build_protos.sh <path to nanopb download>`
12 changes: 12 additions & 0 deletions GoogleDataTransportCCTSupport/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Google Data Transport CCT Support Lib

This library is for internal Google use only. It allows the logging of data and
telemetry from Google SDKs.

## Prereqs

- Install [cocoapod-generate](https://github.com/square/cocoapods-generate)

## To develop

- Run `generate_project.sh` after installing the prereqs
Loading