summaryrefslogtreecommitdiff
path: root/platform/darwin/src/MGLSDKMetricsManager.m
blob: 664bc373e4129a717137d80660abe5a002e59646 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#import "MGLSDKMetricsManager_Private.h"
#import "MGLNetworkConfiguration_Private.h"
#if TARGET_OS_IOS
#import "MGLMapboxEvents.h"
#import <mach-o/arch.h>
#import <sys/utsname.h>
#import <UIKit/UIKit.h>
#endif

NSString* MGLStringFromMetricType(MGLMetricType metricType) {
    NSString *eventName;
    
    switch (metricType) {
        case MGLMetricTypePerformance:
            eventName = kMGLDownloadPerformanceEvent;
            break;
    }
    return eventName;
}

// Taken verbatim from NXFreeArchInfo header documentation
static void MGLFreeArchInfo(const NXArchInfo *x)
{
    const NXArchInfo *p;

    p = NXGetAllArchInfos();
    while(p->name != NULL){
        if(x == p)
            return;
        p++;
    }
    free((char *)x->description);
    free((NXArchInfo *)x);
}

@interface MGLMetricsManager() <MGLNetworkConfigurationMetricsDelegate>

@property (strong, nonatomic) NSDictionary *metadata;

@end

@implementation MGLMetricsManager

+ (instancetype)sharedManager
{
    static dispatch_once_t once;
    static MGLMetricsManager *sharedConfiguration;
    dispatch_once(&once, ^{
        sharedConfiguration = [[self alloc] init];
        [MGLNetworkConfiguration sharedManager].metricsDelegate = sharedConfiguration;
#if TARGET_OS_IOS
        UIDevice *currentDevice = [UIDevice currentDevice];
        
        NSString *osVersion = currentDevice.systemVersion;
        
        NSString *screenSize = [NSString stringWithFormat:@"%.fx%.f", [UIScreen mainScreen].bounds.size.width,
                                [UIScreen mainScreen].bounds.size.height];
        
        NSLocale *currentLocale = [NSLocale currentLocale];
        
        NSString *country = [currentLocale objectForKey:NSLocaleCountryCode] ?: @"unknown";
        
        NSString *device = deviceName();
        
        NSString *abi = @"unknown";
        
        {
            const NXArchInfo *localArchInfo = NXGetLocalArchInfo();
        
            if (localArchInfo) {
                abi = @(localArchInfo->description);

                NSProcessInfo *processInfo = [NSProcessInfo processInfo];

                // Although NXFreeArchInfo appears to be weakly linked, it does
                // not have the weak_import attribute, so check the OS version.
                if (&NXFreeArchInfo && [processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){10, 0, 0}]) {
                    NXFreeArchInfo(localArchInfo);
                } else {
                    MGLFreeArchInfo(localArchInfo);
                }
            }
        }
        
        NSString *ram = [NSString stringWithFormat:@"%llu", [NSProcessInfo processInfo].physicalMemory];
        
        NSString *os = currentDevice.systemName;
        
        sharedConfiguration.metadata = @{ @"version" : osVersion,
                                          @"screenSize" : screenSize,
                                          @"country" : country,
                                          @"device" : device,
                                          @"abi" : abi,
                                          @"brand" : @"Apple",
                                          @"ram" : ram,
                                          @"os" : os
                                          };
#endif
    });
    return sharedConfiguration;
}

- (void)handleMetricsEvent:(MGLMetricType)metricType withAttributes:(NSDictionary *)attributes {
    if ([self.delegate metricsManager:self shouldHandleMetric:metricType]) {
        [self.delegate metricsManager:self didCollectMetric:metricType withAttributes:attributes];
    }
}

#if TARGET_OS_IOS
- (void)pushMetric:(MGLMetricType)metricType withAttributes:(NSDictionary *)attributes {
    NSString *eventName = MGLStringFromMetricType(metricType);
    NSMutableDictionary *mutableAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
    [mutableAttributes setObject:self.metadata forKey:@"metadata"];
    
    [MGLMapboxEvents pushEvent:eventName withAttributes:mutableAttributes];
}

NSString* deviceName()
{
    struct utsname systemInfo;
    uname(&systemInfo);
    
    return [NSString stringWithCString:systemInfo.machine
                              encoding:NSUTF8StringEncoding];
}
#endif

- (void)networkConfiguration:(MGLNetworkConfiguration *)networkConfiguration didGenerateMetricEvent:(NSDictionary *)metricEvent {
    [self handleMetricsEvent:MGLMetricTypePerformance withAttributes:metricEvent];
}

@end