Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// Copyright 2020 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
 
15
#import "FirebasePerformance/Sources/Loggers/FPRGDTRateLimiter.h"
16
#import "FirebasePerformance/Sources/Loggers/FPRGDTRateLimiter+Private.h"
17
 
18
#import <Foundation/Foundation.h>
19
#import <UIKit/UIKit.h>
20
 
21
#import "FirebasePerformance/Sources/AppActivity/FPRAppActivityTracker.h"
22
#import "FirebasePerformance/Sources/Common/FPRPerfDate.h"
23
#import "FirebasePerformance/Sources/Loggers/FPRGDTEvent.h"
24
 
25
#import <GoogleDataTransport/GoogleDataTransport.h>
26
 
27
@interface FPRGDTRateLimiter ()
28
 
29
/**
30
 * Internal date object for setting the time of transformers, which will be used for setting the
31
 * time for trace events and network events.
32
 */
33
@property(nonatomic) id<FPRDate> date;
34
 
35
@end
36
 
37
@implementation FPRGDTRateLimiter
38
 
39
- (instancetype)initWithDate:(id<FPRDate>)date {
40
  FPRGDTRateLimiter *transformer = [[self.class alloc] init];
41
  transformer.date = date;
42
  transformer.lastTraceEventTime = [date now];
43
  transformer.lastNetworkEventTime = [date now];
44
  return transformer;
45
}
46
 
47
- (instancetype)init {
48
  self = [super init];
49
  if (self) {
50
    _date = [[FPRPerfDate alloc] init];
51
 
52
    // Set lastTraceEventTime to default as this would get reset once we receive the first event.
53
    _lastTraceEventTime = [_date now];
54
    _lastNetworkEventTime = [_date now];
55
 
56
    _configurations = [FPRConfigurations sharedInstance];
57
 
58
    _allowedTraceEventsCount = [_configurations foregroundEventCount];
59
    _allowedNetworkEventsCount = [_configurations foregroundNetworkEventCount];
60
    if ([FPRAppActivityTracker sharedInstance].applicationState == FPRApplicationStateBackground) {
61
      _allowedTraceEventsCount = [_configurations backgroundEventCount];
62
      _allowedNetworkEventsCount = [_configurations backgroundNetworkEventCount];
63
    }
64
  }
65
  return self;
66
}
67
 
68
#pragma mark - Transformer methods
69
/**
70
 * Rate limit PerfMetric Events based on rate limiting logic, event that should be
71
 * dropped will return nil in this transformer.
72
 *
73
 * @param logEvent The event to be evaluated by rate limiting logic.
74
 * @return A transformed event, or nil if the transformation dropped the event.
75
 */
76
- (GDTCOREvent *)transformGDTEvent:(nonnull GDTCOREvent *)logEvent {
77
  if ([logEvent.dataObject isKindOfClass:[FPRGDTEvent class]]) {
78
    FPRGDTEvent *gdtEvent = (FPRGDTEvent *)logEvent.dataObject;
79
    firebase_perf_v1_PerfMetric perfMetric = gdtEvent.metric;
80
 
81
    if (perfMetric.has_trace_metric) {
82
      firebase_perf_v1_TraceMetric traceMetric = perfMetric.trace_metric;
83
      // If it is an internal trace event, skip rate limiting.
84
      if (traceMetric.is_auto) {
85
        return logEvent;
86
      }
87
    }
88
  }
89
 
90
  CGFloat rate = [self resolvedTraceRate];
91
  NSInteger eventCount = self.allowedTraceEventsCount;
92
  NSInteger eventBurstSize = self.traceEventBurstSize;
93
  NSDate *currentTime = [self.date now];
94
  NSTimeInterval interval = [currentTime timeIntervalSinceDate:self.lastTraceEventTime];
95
  if ([self isNetworkEvent:logEvent]) {
96
    rate = [self resolvedNetworkRate];
97
    interval = [currentTime timeIntervalSinceDate:self.lastNetworkEventTime];
98
    eventCount = self.allowedNetworkEventsCount;
99
    eventBurstSize = self.networkEventburstSize;
100
  }
101
 
102
  eventCount = [self numberOfAllowedEvents:eventCount
103
                              timeInterval:interval
104
                                 burstSize:eventBurstSize
105
                                 eventRate:rate];
106
 
107
  // Dispatch events only if the allowedEventCount is greater than zero, else drop the event.
108
  if (eventCount > 0) {
109
    if ([self isNetworkEvent:logEvent]) {
110
      self.allowedNetworkEventsCount = --eventCount;
111
      self.lastNetworkEventTime = currentTime;
112
    } else {
113
      self.allowedTraceEventsCount = --eventCount;
114
      self.lastTraceEventTime = currentTime;
115
    }
116
    return logEvent;
117
  }
118
 
119
  // Find the type of the log event.
120
  FPRAppActivityTracker *appActivityTracker = [FPRAppActivityTracker sharedInstance];
121
  NSString *counterName = kFPRAppCounterNameTraceEventsRateLimited;
122
  if ([self isNetworkEvent:logEvent]) {
123
    counterName = kFPRAppCounterNameNetworkTraceEventsRateLimited;
124
  }
125
  [appActivityTracker.activeTrace incrementMetric:counterName byInt:1];
126
 
127
  return nil;
128
}
129
 
130
/**
131
 * Calculates the number of allowed events given the time interval, rate and burst size. Token rate
132
 * limiting algorithm implementation.
133
 *
134
 * @param allowedEventsCount Allowed events count on top of which new event count will be added.
135
 * @param timeInterval Time interval for which event count needs to be calculated.
136
 * @param burstSize Maximum number of events that can be allowed at any moment in time.
137
 * @param rate Rate at which events should be added.
138
 * @return Number of allowed events calculated.
139
 */
140
- (NSInteger)numberOfAllowedEvents:(NSInteger)allowedEventsCount
141
                      timeInterval:(NSTimeInterval)timeInterval
142
                         burstSize:(NSInteger)burstSize
143
                         eventRate:(CGFloat)rate {
144
  NSTimeInterval minutesPassed = timeInterval / 60;
145
  NSInteger newTokens = MAX(0, round(minutesPassed * rate));
146
  NSInteger calculatedAllowedEventsCount = MIN(allowedEventsCount + newTokens, burstSize);
147
  return calculatedAllowedEventsCount;
148
}
149
 
150
#pragma mark - Trace event rate related methods
151
 
152
/**
153
 * Rate at which the trace events can be accepted for a given log source.
154
 *
155
 * @return Event rate for the log source. This is based on the application's background or
156
 *  foreground state.
157
 */
158
- (CGFloat)resolvedTraceRate {
159
  if (self.overrideRate > 0) {
160
    return self.overrideRate;
161
  }
162
 
163
  NSInteger eventCount = [self.configurations foregroundEventCount];
164
  NSInteger timeLimitInMinutes = [self.configurations foregroundEventTimeLimit];
165
 
166
  if ([FPRAppActivityTracker sharedInstance].applicationState == FPRApplicationStateBackground) {
167
    eventCount = [self.configurations backgroundEventCount];
168
    timeLimitInMinutes = [self.configurations backgroundEventTimeLimit];
169
  }
170
 
171
  CGFloat resolvedRate = eventCount / timeLimitInMinutes;
172
  self.traceEventBurstSize = eventCount;
173
  return resolvedRate;
174
}
175
 
176
/**
177
 * Rate at which the network events can be accepted for a given log source.
178
 *
179
 * @return Network event rate for the log source. This is based on the application's background or
180
 *  foreground state.
181
 */
182
- (CGFloat)resolvedNetworkRate {
183
  if (self.overrideNetworkRate > 0) {
184
    return self.overrideNetworkRate;
185
  }
186
 
187
  NSInteger eventCount = [self.configurations foregroundNetworkEventCount];
188
  NSInteger timeLimitInMinutes = [self.configurations foregroundNetworkEventTimeLimit];
189
 
190
  if ([FPRAppActivityTracker sharedInstance].applicationState == FPRApplicationStateBackground) {
191
    eventCount = [self.configurations backgroundNetworkEventCount];
192
    timeLimitInMinutes = [self.configurations backgroundNetworkEventTimeLimit];
193
  }
194
 
195
  CGFloat resolvedRate = eventCount / timeLimitInMinutes;
196
  self.networkEventburstSize = eventCount;
197
  return resolvedRate;
198
}
199
 
200
#pragma mark - Util methods
201
 
202
/**
203
 * Given an event, returns if it is a network event. No, otherwise.
204
 *
205
 * @param logEvent The event to transform.
206
 * @return Yes if the event is a network event. Otherwise, No.
207
 */
208
- (BOOL)isNetworkEvent:(GDTCOREvent *)logEvent {
209
  if ([logEvent.dataObject isKindOfClass:[FPRGDTEvent class]]) {
210
    FPRGDTEvent *gdtEvent = (FPRGDTEvent *)logEvent.dataObject;
211
    firebase_perf_v1_PerfMetric perfMetric = gdtEvent.metric;
212
    if (perfMetric.has_network_request_metric) {
213
      return YES;
214
    }
215
  }
216
  return NO;
217
}
218
 
219
@end