Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RUMM-2169 Isolate Logging feature from Core's configuration and dependencies #877

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions Sources/Datadog/Core/FeaturesConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ internal struct FeaturesConfiguration {
}

struct Logging {
let common: Common
let uploadURL: URL
let logEventMapper: LogEventMapper?
}
Expand Down Expand Up @@ -171,7 +170,6 @@ extension FeaturesConfiguration {

if configuration.loggingEnabled {
logging = Logging(
common: common,
uploadURL: try ifValid(endpointURLString: logsEndpoint.url),
logEventMapper: configuration.logEventMapper
)
Expand Down
5 changes: 3 additions & 2 deletions Sources/Datadog/CrashReporting/CrashReporter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,16 @@ internal class CrashReporter {
convenience init?(
crashReportingFeature: CrashReportingFeature,
loggingFeature: LoggingFeature?,
rumFeature: RUMFeature?
rumFeature: RUMFeature?,
context: DatadogV1Context
) {
let loggingOrRUMIntegration: CrashReportingIntegration?

// If RUM rum is enabled prefer it for sending crash reports, otherwise use Logging feature.
if let rumFeature = rumFeature {
loggingOrRUMIntegration = CrashReportingWithRUMIntegration(rumFeature: rumFeature)
} else if let loggingFeature = loggingFeature {
loggingOrRUMIntegration = CrashReportingWithLoggingIntegration(loggingFeature: loggingFeature)
loggingOrRUMIntegration = CrashReportingWithLoggingIntegration(loggingFeature: loggingFeature, context: context)
} else {
loggingOrRUMIntegration = nil
}
Expand Down
3 changes: 2 additions & 1 deletion Sources/Datadog/Datadog.swift
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,8 @@ public class Datadog {
Global.crashReporter = CrashReporter(
crashReportingFeature: crashReportingFeature,
loggingFeature: logging,
rumFeature: rum
rumFeature: rum,
context: core.v1Context
)

Global.crashReporter?.sendCrashReportIfFound()
Expand Down
13 changes: 8 additions & 5 deletions Sources/Datadog/DatadogCore/DatadogCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ internal final class DatadogCore {

private var v1Features: [String: Any] = [:]

/// The SDK Context for V1.
internal let v1Context: DatadogV1Context

/// Creates a core instance.
///
/// - Parameters:
Expand All @@ -66,6 +69,7 @@ internal final class DatadogCore {
self.rootDirectory = rootDirectory
self.configuration = configuration
self.dependencies = dependencies
self.v1Context = DatadogV1Context(configuration: configuration, dependencies: dependencies)
}

/// Sets current user information.
Expand Down Expand Up @@ -127,11 +131,6 @@ extension DatadogCore: DatadogV1CoreProtocol {
telemetry: telemetry
)

let v1Context = DatadogV1Context(
configuration: configuration,
dependencies: dependencies
)

let upload = FeatureUpload(
featureName: uploadConfiguration.featureName,
storage: storage,
Expand All @@ -158,6 +157,10 @@ extension DatadogCore: DatadogV1CoreProtocol {
let key = String(describing: T.self)
return v1Features[key] as? T
}

var context: DatadogV1Context? {
return v1Context
}
}

internal protocol V1Feature {
Expand Down
31 changes: 31 additions & 0 deletions Sources/Datadog/DatadogInternal/DatadogV1Context.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import Foundation
/// - different values for V1 context need to be read either from common configuration or through shared dependencies (providers);
/// - V1 context is not asynchronous, and some providers block their threads for getting their value.
///
/// `DatadogV1Context` can be safely captured during component initialization. It will never change during component's lifespan, meaning that:
/// - exposed static configuration won't change;
/// - bundled provider references won't change (although the value they provide will be different over time).
internal struct DatadogV1Context {
private let configuration: CoreConfiguration
private let dependencies: CoreDependencies
Expand All @@ -20,7 +23,12 @@ internal struct DatadogV1Context {
self.configuration = configuration
self.dependencies = dependencies
}
}

// MARK: - Configuration

/// This extension bundles different parts of the SDK core configuration.
internal extension DatadogV1Context {
// MARK: - Datadog Specific

/// The client token allowing for data uploads to [Datadog Site](https://docs.datadoghq.com/getting_started/site/).
Expand Down Expand Up @@ -51,6 +59,29 @@ internal struct DatadogV1Context {
/// The name of the application, read from `Info.plist` (`CFBundleExecutable`).
var applicationName: String { configuration.applicationName }

/// The bundle identifier, read from `Info.plist` (`CFBundleIdentifier`).
var applicationBundleIdentifier: String { configuration.applicationBundleIdentifier }
}

// MARK: - Providers

/// This extension bundles different providers managed by the SDK core.
internal extension DatadogV1Context {
/// Current device information.
var mobileDevice: MobileDevice { dependencies.mobileDevice }

/// Time provider.
var dateProvider: DateProvider { dependencies.dateProvider }

/// NTP time correction provider.
var dateCorrector: DateCorrectorType { dependencies.dateCorrector }

/// Network information provider.
var networkConnectionInfoProvider: NetworkConnectionInfoProviderType { dependencies.networkConnectionInfoProvider }

/// Carrier information provider.
var carrierInfoProvider: CarrierInfoProviderType { dependencies.carrierInfoProvider }

/// User information provider.
var userInfoProvider: UserInfoProvider { dependencies.userInfoProvider }
}
7 changes: 7 additions & 0 deletions Sources/Datadog/DatadogInternal/DatadogV1CoreProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ internal protocol DatadogV1CoreProtocol: DatadogCoreProtocol {
/// - type: The feature instance type.
/// - Returns: The feature if any.
func feature<T>(_ type: T.Type) -> T?

/// The SDK context created upon core initialization or `nil` if SDK was not yet initialized.
var context: DatadogV1Context? { get }
}

extension NOOPDatadogCore: DatadogV1CoreProtocol {
Expand All @@ -43,4 +46,8 @@ extension NOOPDatadogCore: DatadogV1CoreProtocol {
func feature<T>(_ type: T.Type) -> T? {
return nil
}

var context: DatadogV1Context? {
return nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,32 @@ internal struct CrashReportingWithLoggingIntegration: CrashReportingIntegration
private let dateProvider: DateProvider
private let dateCorrector: DateCorrectorType

/// Global configuration set for the SDK (service name, environment, application version, ...)
private let configuration: FeaturesConfiguration.Common
private let context: DatadogV1Context

init(loggingFeature: LoggingFeature) {
init(loggingFeature: LoggingFeature, context: DatadogV1Context) {
self.init(
logOutput: LogFileOutput(
fileWriter: loggingFeature.storage.arbitraryAuthorizedWriter,
// The RUM Errors integration is not set for this instance of the `LogFileOutput` we don't want to
// issue additional RUM Errors for crash reports. Those are send through `CrashReportingWithRUMIntegration`.
rumErrorsIntegration: nil
),
dateProvider: loggingFeature.dateProvider,
dateCorrector: loggingFeature.dateCorrector,
configuration: loggingFeature.configuration.common
dateProvider: context.dateProvider,
dateCorrector: context.dateCorrector,
context: context
)
}

init(
logOutput: LogOutput,
dateProvider: DateProvider,
dateCorrector: DateCorrectorType,
configuration: FeaturesConfiguration.Common
context: DatadogV1Context
) {
self.logOutput = logOutput
self.dateProvider = dateProvider
self.dateCorrector = dateCorrector
self.configuration = configuration
self.context = context
}

func send(crashReport: DDCrashReport, with crashContext: CrashContext) {
Expand Down Expand Up @@ -85,12 +84,12 @@ internal struct CrashReportingWithLoggingIntegration: CrashReportingIntegration
message: crashReport.message,
stack: crashReport.stack
),
serviceName: configuration.serviceName,
environment: configuration.environment,
serviceName: context.service,
environment: context.env,
loggerName: Constants.loggerName,
loggerVersion: configuration.sdkVersion,
loggerVersion: context.sdkVersion,
threadName: nil,
applicationVersion: configuration.applicationVersion,
applicationVersion: context.version,
userInfo: .init(
id: user?.id,
name: user?.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ internal struct TracingWithLoggingIntegration {
/// Actual `LogOutput` bridged to `LoggingFeature`.
let loggingOutput: LogOutput

init(tracingFeature: TracingFeature, tracerConfiguration: Tracer.Configuration, loggingFeature: LoggingFeature) {
init(
tracingFeature: TracingFeature,
tracerConfiguration: Tracer.Configuration,
loggingFeature: LoggingFeature,
context: DatadogV1Context
) {
self.init(
logBuilder: LogEventBuilder(
sdkVersion: tracingFeature.configuration.common.sdkVersion,
Expand All @@ -34,7 +39,7 @@ internal struct TracingWithLoggingIntegration {
userInfoProvider: tracingFeature.userInfoProvider,
networkConnectionInfoProvider: tracerConfiguration.sendNetworkInfo ? tracingFeature.networkConnectionInfoProvider : nil,
carrierInfoProvider: tracerConfiguration.sendNetworkInfo ? tracingFeature.carrierInfoProvider : nil,
dateCorrector: loggingFeature.dateCorrector,
dateCorrector: context.dateCorrector,
logEventMapper: loggingFeature.configuration.logEventMapper
),
loggingOutput: LogFileOutput(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,26 @@ public extension WKUserContentController {
///
/// - Parameter hosts: a list of hosts instrumented with Browser SDK to capture Datadog events from
func trackDatadogEvents(in hosts: Set<String>, sdk core: DatadogCoreProtocol = defaultDatadogCore) {
do {
try trackDatadogEventsOrThrow(in: hosts, sdk: core)
} catch {
consolePrint("\(error)")
}
}

private func trackDatadogEventsOrThrow(in hosts: Set<String>, sdk core: DatadogCoreProtocol) throws {
guard let context = core.v1.context else {
throw ProgrammerError(
description: "`Datadog.initialize()` must be called prior to `trackDatadogEvents(in:)`."
)
}

addDatadogMessageHandler(
allowedWebViewHosts: hosts,
hostsSanitizer: HostsSanitizer(),
loggingFeature: core.v1.feature(LoggingFeature.self),
rumFeature: core.v1.feature(RUMFeature.self)
rumFeature: core.v1.feature(RUMFeature.self),
context: context
)
}

Expand All @@ -53,7 +68,8 @@ public extension WKUserContentController {
allowedWebViewHosts: Set<String>,
hostsSanitizer: HostsSanitizing,
loggingFeature: LoggingFeature?,
rumFeature: RUMFeature?
rumFeature: RUMFeature?,
context: DatadogV1Context
) {
guard !isTracking else {
userLogger.warn("`trackDatadogEvents(in:)` was called more than once for the same WebView. Second call will be ignored. Make sure you call it only once.")
Expand All @@ -68,10 +84,10 @@ public extension WKUserContentController {
if let loggingFeature = loggingFeature {
logEventConsumer = DefaultWebLogEventConsumer(
userLogsWriter: loggingFeature.storage.writer,
dateCorrector: loggingFeature.dateCorrector,
dateCorrector: context.dateCorrector,
rumContextProvider: globalRUMMonitor?.contextProvider,
applicationVersion: loggingFeature.configuration.common.applicationVersion,
environment: loggingFeature.configuration.common.environment
applicationVersion: context.version,
environment: context.env
)
}

Expand Down
40 changes: 22 additions & 18 deletions Sources/Datadog/Logger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -399,15 +399,19 @@ public class Logger {
}

private func buildOrThrow(in core: DatadogCoreProtocol) throws -> Logger {
guard let context = core.v1.context else {
throw ProgrammerError(
description: "`Datadog.initialize()` must be called prior to `Logger.builder.build()`."
)
}

guard let loggingFeature = core.v1.feature(LoggingFeature.self) else {
throw ProgrammerError(
description: Datadog.isInitialized
? "`Logger.builder.build()` produces a non-functional logger, as the logging feature is disabled."
: "`Datadog.initialize()` must be called prior to `Logger.builder.build()`."
description: "`Logger.builder.build()` produces a non-functional logger, as the logging feature is disabled."
)
}

let (logBuilder, logOutput) = resolveLogBuilderAndOutput(for: loggingFeature) ?? (nil, nil)
let (logBuilder, logOutput) = resolveLogBuilderAndOutput(for: loggingFeature, context: context) ?? (nil, nil)

// RUMM-2133 Note: strong feature coupling while migrating to v2.
// In v2 active span will be provided in context from feature scope.
Expand All @@ -417,24 +421,24 @@ public class Logger {
return Logger(
logBuilder: logBuilder,
logOutput: logOutput,
dateProvider: loggingFeature.dateProvider,
identifier: resolveLoggerName(for: loggingFeature),
dateProvider: context.dateProvider,
identifier: resolveLoggerName(with: context),
rumContextIntegration: (rumEnabled && bundleWithRUM) ? LoggingWithRUMContextIntegration() : nil,
activeSpanIntegration: (tracingEnabled && bundleWithTrace) ? LoggingWithActiveSpanIntegration() : nil
)
}

private func resolveLogBuilderAndOutput(for loggingFeature: LoggingFeature) -> (LogEventBuilder, LogOutput)? {
private func resolveLogBuilderAndOutput(for loggingFeature: LoggingFeature, context: DatadogV1Context) -> (LogEventBuilder, LogOutput)? {
let logBuilder = LogEventBuilder(
sdkVersion: loggingFeature.configuration.common.sdkVersion,
applicationVersion: loggingFeature.configuration.common.applicationVersion,
environment: loggingFeature.configuration.common.environment,
serviceName: serviceName ?? loggingFeature.configuration.common.serviceName,
loggerName: resolveLoggerName(for: loggingFeature),
userInfoProvider: loggingFeature.userInfoProvider,
networkConnectionInfoProvider: sendNetworkInfo ? loggingFeature.networkConnectionInfoProvider : nil,
carrierInfoProvider: sendNetworkInfo ? loggingFeature.carrierInfoProvider : nil,
dateCorrector: loggingFeature.dateCorrector,
sdkVersion: context.sdkVersion,
applicationVersion: context.version,
environment: context.env,
serviceName: serviceName ?? context.service,
loggerName: resolveLoggerName(with: context),
userInfoProvider: context.userInfoProvider,
networkConnectionInfoProvider: sendNetworkInfo ? context.networkConnectionInfoProvider : nil,
carrierInfoProvider: sendNetworkInfo ? context.carrierInfoProvider : nil,
dateCorrector: context.dateCorrector,
logEventMapper: loggingFeature.configuration.logEventMapper
)

Expand Down Expand Up @@ -470,8 +474,8 @@ public class Logger {
}
}

private func resolveLoggerName(for loggingFeature: LoggingFeature) -> String {
return loggerName ?? loggingFeature.configuration.common.applicationBundleIdentifier
private func resolveLoggerName(with context: DatadogV1Context) -> String {
return loggerName ?? context.applicationBundleIdentifier
}
}
}
16 changes: 1 addition & 15 deletions Sources/Datadog/Logging/LoggingFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,6 @@ internal final class LoggingFeature: V1FeatureInitializable {

let configuration: Configuration

// MARK: - Dependencies

let dateProvider: DateProvider
let dateCorrector: DateCorrectorType
let userInfoProvider: UserInfoProvider
let networkConnectionInfoProvider: NetworkConnectionInfoProviderType
let carrierInfoProvider: CarrierInfoProviderType

// MARK: - Components

/// Log files storage.
Expand All @@ -36,19 +28,13 @@ internal final class LoggingFeature: V1FeatureInitializable {
storage: FeatureStorage,
upload: FeatureUpload,
configuration: Configuration,
/// TODO: RUMM-2169 Remove `commonDependencies` from `V1FeatureInitializable` interface when all Features are migrated to use `DatadogV1Context`:
commonDependencies: FeaturesCommonDependencies,
telemetry: Telemetry?
) {
// Configuration
self.configuration = configuration

// Bundle dependencies
self.dateProvider = commonDependencies.dateProvider
self.dateCorrector = commonDependencies.dateCorrector
self.userInfoProvider = commonDependencies.userInfoProvider
self.networkConnectionInfoProvider = commonDependencies.networkConnectionInfoProvider
self.carrierInfoProvider = commonDependencies.carrierInfoProvider

// Initialize stacks
self.storage = storage
self.upload = upload
Expand Down
Loading