FIRPerformance.m 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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. #import "FirebasePerformance/Sources/Public/FirebasePerformance/FIRPerformance.h"
  15. #import "FirebasePerformance/Sources/FIRPerformance+Internal.h"
  16. #import "FirebasePerformance/Sources/FIRPerformance_Private.h"
  17. #import "FirebasePerformance/Sources/Common/FPRConstants.h"
  18. #import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h"
  19. #import "FirebasePerformance/Sources/FPRClient+Private.h"
  20. #import "FirebasePerformance/Sources/FPRClient.h"
  21. #import "FirebasePerformance/Sources/FPRConsoleLogger.h"
  22. #import "FirebasePerformance/Sources/FPRDataUtils.h"
  23. #import "FirebasePerformance/Sources/Instrumentation/FPRInstrumentation.h"
  24. #import "FirebasePerformance/Sources/Timer/FIRTrace+Internal.h"
  25. static NSString *const kFirebasePerfErrorDomain = @"com.firebase.perf";
  26. @implementation FIRPerformance
  27. #pragma mark - Public methods
  28. + (void)load {
  29. [FIRApp registerInternalLibrary:(Class<FIRLibrary>)self withName:@"firebase-performance"];
  30. }
  31. + (NSArray<FIRComponent *> *)componentsToRegister {
  32. FIRDependency *crashlyticsDep =
  33. [FIRDependency dependencyWithProtocol:@protocol(FIRCrashlyticsInterop)];
  34. FIRComponentCreationBlock creationBlock =
  35. ^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) {
  36. id<FIRCrashlyticsInterop> crashlytics = FIR_COMPONENT(FIRCrashlyticsInterop, container);
  37. *isCacheable = YES;
  38. return [[FIRPerformance alloc] initWithCrashlytics:crashlytics];
  39. };
  40. FIRComponent *component =
  41. [FIRComponent componentWithProtocol:@protocol(FIRPerformanceInstanceProvider)
  42. instantiationTiming:FIRInstantiationTimingLazy
  43. dependencies:@[ crashlyticsDep ]
  44. creationBlock:creationBlock];
  45. return @[ component ];
  46. }
  47. + (instancetype)sharedInstance {
  48. // The container will return the same instance since isCacheable is set
  49. FIRApp *defaultApp = [FIRApp defaultApp]; // Missing configure will be logged here.
  50. // Get the instance from the `FIRApp`'s container. This will create a new instance the
  51. // first time it is called, and since `isCacheable` is set in the component creation
  52. // block, it will return the existing instance on subsequent calls.
  53. id<FIRPerformanceInstanceProvider> instance =
  54. FIR_COMPONENT(FIRPerformanceInstanceProvider, defaultApp.container);
  55. // In the component creation block, we return an instance of `FIRCrashlytics`. Cast it and
  56. // return it.
  57. return (FIRPerformance *)instance;
  58. }
  59. + (FIRTrace *)startTraceWithName:(NSString *)name {
  60. FIRTrace *trace = [[self sharedInstance] traceWithName:name];
  61. [trace start];
  62. return trace;
  63. }
  64. - (FIRTrace *)traceWithName:(NSString *)name {
  65. if (![self isPerfConfigured]) {
  66. FPRLogError(kFPRTraceNotCreated, @"Failed creating trace %@. Firebase is not configured.",
  67. name);
  68. [NSException raise:kFirebasePerfErrorDomain
  69. format:@"The default Firebase app has not yet been configured. Add [FirebaseApp "
  70. @"configure] to your application initialization."];
  71. return nil;
  72. }
  73. FIRTrace *trace = [[FIRTrace alloc] initWithName:name];
  74. return trace;
  75. }
  76. /**
  77. * Checks if the SDK has been successfully configured.
  78. *
  79. * @return YES if SDK is configured successfully, otherwise NO.
  80. */
  81. - (BOOL)isPerfConfigured {
  82. return self.fprClient.isConfigured;
  83. }
  84. #pragma mark - Internal methods
  85. - (instancetype)initWithCrashlytics:(id<FIRCrashlyticsInterop>)crashlytics {
  86. self = [super init];
  87. if (self) {
  88. _customAttributes = [[NSMutableDictionary<NSString *, NSString *> alloc] init];
  89. _customAttributesSerialQueue =
  90. dispatch_queue_create("com.google.perf.customAttributes", DISPATCH_QUEUE_SERIAL);
  91. _fprClient = [FPRClient sharedInstance];
  92. _crashlytics = crashlytics;
  93. }
  94. return self;
  95. }
  96. - (BOOL)isDataCollectionEnabled {
  97. return [FPRConfigurations sharedInstance].isDataCollectionEnabled;
  98. }
  99. - (void)setDataCollectionEnabled:(BOOL)dataCollectionEnabled {
  100. BOOL performanceDataCollectionEnabled = self.dataCollectionEnabled;
  101. if (performanceDataCollectionEnabled != dataCollectionEnabled) {
  102. [[FPRConfigurations sharedInstance] setDataCollectionEnabled:dataCollectionEnabled];
  103. }
  104. }
  105. - (BOOL)isInstrumentationEnabled {
  106. return self.fprClient.isSwizzled || [FPRConfigurations sharedInstance].isInstrumentationEnabled;
  107. }
  108. - (void)setInstrumentationEnabled:(BOOL)instrumentationEnabled {
  109. [[FPRConfigurations sharedInstance] setInstrumentationEnabled:instrumentationEnabled];
  110. if (instrumentationEnabled) {
  111. [self.fprClient checkAndStartInstrumentation];
  112. } else {
  113. if (self.fprClient.isSwizzled) {
  114. FPRLogError(kFPRInstrumentationDisabledAfterConfigure,
  115. @"Failed to disable instrumentation because Firebase Performance has already "
  116. @"been configured. It will be disabled when the app restarts.");
  117. }
  118. }
  119. }
  120. #pragma mark - Custom attributes related methods
  121. - (NSDictionary<NSString *, NSString *> *)attributes {
  122. return [self.customAttributes copy];
  123. }
  124. - (void)setValue:(NSString *)value forAttribute:(nonnull NSString *)attribute {
  125. NSString *validatedName = FPRReservableAttributeName(attribute);
  126. NSString *validatedValue = FPRValidatedAttributeValue(value);
  127. BOOL canAddAttribute = YES;
  128. if (validatedName == nil) {
  129. FPRLogError(kFPRAttributeNoName,
  130. @"Failed to initialize because of a nil or zero length attribute name.");
  131. canAddAttribute = NO;
  132. }
  133. if (validatedValue == nil) {
  134. FPRLogError(kFPRAttributeNoValue,
  135. @"Failed to initialize because of a nil or zero length attribute value.");
  136. canAddAttribute = NO;
  137. }
  138. if (self.customAttributes.allKeys.count >= kFPRMaxGlobalCustomAttributesCount) {
  139. FPRLogError(kFPRMaxAttributesReached,
  140. @"Only %d attributes allowed. Already reached maximum attribute count.",
  141. kFPRMaxGlobalCustomAttributesCount);
  142. canAddAttribute = NO;
  143. }
  144. if (canAddAttribute) {
  145. // Ensure concurrency during update of attributes.
  146. dispatch_sync(self.customAttributesSerialQueue, ^{
  147. self.customAttributes[validatedName] = validatedValue;
  148. });
  149. }
  150. }
  151. - (NSString *)valueForAttribute:(NSString *)attribute {
  152. // TODO(b/175053654): Should this be happening on the serial queue for thread safety?
  153. return self.customAttributes[attribute];
  154. }
  155. - (void)removeAttribute:(NSString *)attribute {
  156. [self.customAttributes removeObjectForKey:attribute];
  157. }
  158. @end