Sources/apm-agent-ios/InstrumentationWrapper.swift (99 lines of code) (raw):

// Copyright © 2022 Elasticsearch BV // // 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 import URLSessionInstrumentation import MemorySampler import CPUSampler import NetworkStatus import OpenTelemetryApi class InstrumentationWrapper { var appMetrics: Any? #if os(iOS) var vcInstrumentation: ViewControllerInstrumentation? var applicationLifecycleInstrumentation: ApplicationLifecycleInstrumentation? #endif #if os(iOS) && !targetEnvironment(macCatalyst) var netstatInjector: NetworkStatusInjector? #endif var urlSessionInstrumentation: URLSessionInstrumentation? let config: AgentConfigManager init(config: AgentConfigManager) { self.config = config #if os(iOS) if config.instrumentation.enableLifecycleEvents { applicationLifecycleInstrumentation = ApplicationLifecycleInstrumentation() } do { if self.config.instrumentation.enableViewControllerInstrumentation { vcInstrumentation = try ViewControllerInstrumentation() } } catch { print("failed to initalize view controller instrumentation: \(error)") } #endif // os(iOS) } func initalize() { #if os(iOS) if #available(iOS 13.0, *) { if config.instrumentation.enableSystemMetrics { _ = MemorySampler() _ = CPUSampler() } if config.instrumentation.enableAppMetricInstrumentation { appMetrics = AppMetrics() if let metrics = appMetrics as? AppMetrics { metrics.receiveReports() } } } #endif if config.instrumentation.enableURLSessionInstrumentation { initializeNetworkInstrumentation() } #if os(iOS) vcInstrumentation?.swizzle() #endif // os(iOS) } private func initializeNetworkInstrumentation() { #if os(iOS) && !targetEnvironment(macCatalyst) do { let netstats = try NetworkStatus() netstatInjector = NetworkStatusInjector(netstat: netstats) } catch { print("failed to initialize network connection status \(error)") } #endif let config = URLSessionInstrumentationConfiguration(shouldRecordPayload: nil, shouldInstrument: nil, nameSpan: { request in if let host = request.url?.host, let method = request.httpMethod { return "\(method) \(host)" } return nil }, shouldInjectTracingHeaders: nil, createdRequest: { _, span in #if os(iOS) && !targetEnvironment(macCatalyst) if let injector = self.netstatInjector { injector.inject(span: span) } #endif }, receivedResponse: { response, _, span in if let httpResponse = response as? HTTPURLResponse { if httpResponse.statusCode >= 400 && httpResponse.statusCode <= 599 { // swiftlint:disable line_length span.addEvent(name: SemanticAttributes.exception.rawValue, attributes: [SemanticAttributes.exceptionType.rawValue: AttributeValue.string("\(httpResponse.statusCode)"), SemanticAttributes.exceptionEscaped.rawValue: AttributeValue.bool(false), SemanticAttributes.exceptionMessage.rawValue: AttributeValue.string(HTTPURLResponse.localizedString(forStatusCode: httpResponse.statusCode)) ]) // swiftlint:enable line_length } } }, receivedError: { error, _, _, span in // swiftlint:disable line_length span.addEvent(name: SemanticAttributes.exception.rawValue, attributes: [SemanticAttributes.exceptionType.rawValue: AttributeValue.string(String(describing: type(of: error))), SemanticAttributes.exceptionEscaped.rawValue: AttributeValue.bool(false), SemanticAttributes.exceptionMessage.rawValue: AttributeValue.string(error.localizedDescription)]) // swiftlint:enable line_length }) urlSessionInstrumentation = URLSessionInstrumentation(configuration: config) } }