Add stub for analytics.

// FREEBIE
This commit is contained in:
Matthew Chen 2017-01-10 16:41:40 -05:00
parent ed98cf2627
commit 2a55075e6c
3 changed files with 268 additions and 0 deletions

120
Utilities/precommit.py Executable file
View file

@ -0,0 +1,120 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import subprocess
import datetime
import argparse
import commands
git_repo_path = os.path.abspath(subprocess.check_output(['git', 'rev-parse', '--show-toplevel']).strip())
def splitall(path):
allparts = []
while 1:
parts = os.path.split(path)
if parts[0] == path: # sentinel for absolute paths
allparts.insert(0, parts[0])
break
elif parts[1] == path: # sentinel for relative paths
allparts.insert(0, parts[1])
break
else:
path = parts[0]
allparts.insert(0, parts[1])
return allparts
def process(filepath):
with open(filepath, 'rt') as f:
text = f.read()
original_text = text
lines = text.split('\n')
while lines and lines[0].startswith('//'):
lines = lines[1:]
text = '\n'.join(lines)
text = text.strip()
header = '''//
// Copyright (c) %s Open Whisper Systems. All rights reserved.
//
''' % (
datetime.datetime.now().year,
)
text = header + text + '\n'
if original_text == text:
return
short_filepath = filepath[len(git_repo_path):]
if short_filepath.startswith(os.sep):
short_filepath = short_filepath[len(os.sep):]
print 'Updating:', short_filepath
with open(filepath, 'wt') as f:
f.write(text)
def should_ignore_path(path):
ignore_paths = [
os.path.join(git_repo_path, '.git')
]
for ignore_path in ignore_paths:
if path.startswith(ignore_path):
return True
for component in splitall(path):
if component.startswith('.'):
return True
if component.endswith('.framework'):
return True
if component in ('Pods', 'ThirdParty', 'Carthage',):
return True
return False
def process_if_appropriate(filepath):
filename = os.path.basename(filepath)
if filename.startswith('.'):
return
file_ext = os.path.splitext(filename)[1]
if file_ext not in ('.h', '.hpp', '.cpp', '.m', '.mm', '.pch', '.swift'):
return
if should_ignore_path(filepath):
return
process(filepath)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Precommit script.')
parser.add_argument('--all', action='store_true', help='process all files in or below current dir')
args = parser.parse_args()
if args.all:
for rootdir, dirnames, filenames in os.walk(git_repo_path):
for filename in filenames:
file_path = os.path.abspath(os.path.join(rootdir, filename))
process_if_appropriate(file_path)
else:
filepaths = []
# Staging
output = commands.getoutput('git diff --cached --name-only --diff-filter=ACMR')
filepaths.extend([line.strip() for line in output.split('\n')])
# Working
output = commands.getoutput('git diff --name-only --diff-filter=ACMR')
filepaths.extend([line.strip() for line in output.split('\n')])
# Only process each path once.
filepaths = sorted(set(filepaths))
for filepath in filepaths:
filepath = os.path.abspath(os.path.join(git_repo_path, filepath))
process_if_appropriate(filepath)

72
src/Util/OWSAnalytics.h Executable file
View file

@ -0,0 +1,72 @@
//
// OWSAnalytics.h
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
typedef NS_ENUM(NSUInteger, OWSAnalyticsSeverity) {
OWSAnalyticsSeverityDebug = 0,
OWSAnalyticsSeverityInfo = 1,
OWSAnalyticsSeverityWarn = 2,
OWSAnalyticsSeverityError = 3,
// I suspect we'll stage the development of our analytics,
// initially building only a minimal solution: an endpoint which
// ignores most requests, and sends only the highest-severity
// events as email to developers.
//
// This "critical" level of severity is intended for that purpose (for now).
//
// We might want to have an additional level of severity for
// critical (crashing) bugs that occur during app startup. These
// events should be sent to the service immediately and the app
// should block until that request completes.
OWSAnalyticsSeverityCritical = 4,
OWSAnalyticsSeverityOff = 5
};
// This is a placeholder. We don't yet serialize or transmit analytics events.
//
// If/when we take this on, we'll want to develop a solution that can be used
// report user activity - especially serious bugs - without compromising user
// privacy in any way. We must _never_ include any identifying information.
@interface OWSAnalytics : NSObject
// description: A non-empty string without any leading whitespace.
// parameters: Optional.
// If non-nil, the keys should all be non-empty NSStrings.
// Values should be NSStrings or NSNumbers.
+ (void)logEvent:(NSString *)description
severity:(OWSAnalyticsSeverity)severity
parameters:(NSDictionary *)parameters
location:(const char *)location;
@end
#define OWSAnalyticsLogEvent(severityLevel, frmt, ...) \
[OWSAnalytics logEvent:[NSString stringWithFormat:frmt, ##__VA_ARGS__] \
severity:severityLevel \
parameters:nil \
location:__PRETTY_FUNCTION__];
#define OWSAnalyticsLogEventWithParameters(severityLevel, frmt, params) \
[OWSAnalytics logEvent:frmt severity:severityLevel parameters:params location:__PRETTY_FUNCTION__];
#define OWSAnalyticsDebug(frmt, ...) OWSAnalyticsLogEvent(OWSAnalyticsSeverityDebug, frmt, ##__VA_ARGS__)
#define OWSAnalyticsDebugWithParameters(description, params) \
OWSAnalyticsLogEventWithParameters(OWSAnalyticsSeverityDebug, description, params)
#define OWSAnalyticsInfo(frmt, ...) OWSAnalyticsLogEvent(OWSAnalyticsSeverityInfo, frmt, ##__VA_ARGS__)
#define OWSAnalyticsInfoWithParameters(description, params) \
OWSAnalyticsLogEventWithParameters(OWSAnalyticsSeverityInfo, description, params)
#define OWSAnalyticsWarn(frmt, ...) OWSAnalyticsLogEvent(OWSAnalyticsSeverityWarn, frmt, ##__VA_ARGS__)
#define OWSAnalyticsWarnWithParameters(description, params) \
OWSAnalyticsLogEventWithParameters(OWSAnalyticsSeverityWarn, description, params)
#define OWSAnalyticsError(frmt, ...) OWSAnalyticsLogEvent(OWSAnalyticsSeverityError, frmt, ##__VA_ARGS__)
#define OWSAnalyticsErrorWithParameters(description, params) \
OWSAnalyticsLogEventWithParameters(OWSAnalyticsSeverityError, description, params)
#define OWSAnalyticsCritical(frmt, ...) OWSAnalyticsLogEvent(OWSAnalyticsSeverityCritical, frmt, ##__VA_ARGS__)
#define OWSAnalyticsCriticalWithParameters(description, params) \
OWSAnalyticsLogEventWithParameters(OWSAnalyticsSeverityCritical, description, params)

76
src/Util/OWSAnalytics.m Executable file
View file

@ -0,0 +1,76 @@
//
// OWSAnalytics.m
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import <CocoaLumberjack/CocoaLumberjack.h>
#import "OWSAnalytics.h"
@implementation OWSAnalytics
+ (instancetype)sharedInstance
{
static OWSAnalytics *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [self new];
// TODO: If we ever log these events to disk,
// we may want to protect these file(s) like TSStorageManager.
});
return instance;
}
+ (void)logEvent:(NSString *)description
severity:(OWSAnalyticsSeverity)severity
parameters:(NSDictionary *)parameters
location:(const char *)location
{
[[self sharedInstance] logEvent:description severity:severity parameters:parameters location:location];
}
- (void)logEvent:(NSString *)description
severity:(OWSAnalyticsSeverity)severity
parameters:(NSDictionary *)parameters
location:(const char *)location
{
DDLogFlag logFlag;
BOOL async = YES;
switch (severity) {
case OWSAnalyticsSeverityDebug:
logFlag = DDLogFlagDebug;
break;
case OWSAnalyticsSeverityInfo:
logFlag = DDLogFlagInfo;
break;
case OWSAnalyticsSeverityWarn:
logFlag = DDLogFlagWarning;
break;
case OWSAnalyticsSeverityError:
logFlag = DDLogFlagError;
async = NO;
break;
case OWSAnalyticsSeverityCritical:
logFlag = DDLogFlagError;
async = NO;
break;
default:
OWSAssert(0);
logFlag = DDLogFlagDebug;
break;
}
// Log the event.
if (!parameters) {
LOG_MAYBE(async, LOG_LEVEL_DEF, logFlag, 0, nil, location, @"%@", description);
} else {
LOG_MAYBE(async, LOG_LEVEL_DEF, logFlag, 0, nil, location, @"%@ %@", description, parameters);
}
// Do nothing. We don't yet serialize or transmit analytics events.
}
@end