Skip to content

Commit f078f10

Browse files
authored
Default to enabled observability (#54)
### Motivation Swift Log/Swift Metrics integration should be enabled by default. And the operator can always pass in a no-op log/metrics backend if they want to discard it. This is important when Configuration is used as a transitive dependency, as there the operator wouldn't have a way to _enable_ observability from this library unless the direct dependency that pulled in Configuration was cooperative. ### Modifications Enabled logging/metrics by default by changing the default parameter values in the reloading providers. ### Result Logs/metrics emitted for reloading providers by default. ### Test Plan Adapted tests.
1 parent 80df713 commit f078f10

File tree

5 files changed

+30
-28
lines changed

5 files changed

+30
-28
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ DerivedData/
77
Package.resolved
88
*.pyc
99
.docc-build
10+
.vscode

Sources/Configuration/Providers/Common/ReloadingFileProviderCore.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,17 +94,17 @@ internal final class ReloadingFileProviderCore<SnapshotType: ConfigSnapshotProto
9494
/// - pollInterval: The interval between timestamp checks.
9595
/// - providerName: The human-readable name of the provider.
9696
/// - fileSystem: The file system to use.
97-
/// - logger: The logger instance, or nil to create a default one.
98-
/// - metrics: The metrics factory, or nil to use a no-op implementation.
97+
/// - logger: The logger instance.
98+
/// - metrics: The metrics factory.
9999
/// - createSnapshot: A closure that creates a snapshot from file data.
100100
/// - Throws: If the initial file load or snapshot creation fails.
101101
internal init(
102102
filePath: FilePath,
103103
pollInterval: Duration,
104104
providerName: String,
105105
fileSystem: any CommonProviderFileSystem,
106-
logger: Logger?,
107-
metrics: (any MetricsFactory)?,
106+
logger: Logger,
107+
metrics: any MetricsFactory,
108108
createSnapshot: @Sendable @escaping (Data) async throws -> SnapshotType
109109
) async throws {
110110
self.filePath = filePath
@@ -114,7 +114,7 @@ internal final class ReloadingFileProviderCore<SnapshotType: ConfigSnapshotProto
114114
self.createSnapshot = createSnapshot
115115

116116
// Set up the logger with metadata
117-
var logger = logger ?? Logger(label: providerName)
117+
var logger = logger
118118
logger[metadataKey: "\(providerName).filePath"] = .string(filePath.lastComponent?.string ?? "<nil>")
119119
logger[metadataKey: "\(providerName).pollInterval.seconds"] = .string(
120120
pollInterval.components.seconds.description
@@ -123,7 +123,7 @@ internal final class ReloadingFileProviderCore<SnapshotType: ConfigSnapshotProto
123123

124124
// Set up metrics
125125
self.metrics = ReloadingFileProviderMetrics(
126-
factory: metrics ?? NOOPMetricsHandler.instance,
126+
factory: metrics,
127127
providerName: providerName
128128
)
129129

Sources/Configuration/Providers/JSON/ReloadingJSONProvider.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ public final class ReloadingJSONProvider: Sendable {
9595
pollInterval: Duration = .seconds(15),
9696
bytesDecoder: some ConfigBytesFromStringDecoder = .base64,
9797
secretsSpecifier: SecretsSpecifier<String, any Sendable> = .none,
98-
logger: Logger? = nil,
99-
metrics: (any MetricsFactory)? = nil
98+
logger: Logger = Logger(label: "ReloadingJSONProvider"),
99+
metrics: any MetricsFactory = MetricsSystem.factory
100100
) async throws {
101101
try await self.init(
102102
filePath: filePath,
@@ -116,17 +116,17 @@ public final class ReloadingJSONProvider: Sendable {
116116
/// - bytesDecoder: A decoder of bytes from a string.
117117
/// - secretsSpecifier: A secrets specifier in case some of the values should be treated as secret.
118118
/// - fileSystem: The underlying file system.
119-
/// - logger: The logger instance to use, or nil to create a default one.
120-
/// - metrics: The metrics factory to use, or nil to use a no-op implementation.
119+
/// - logger: The logger instance to use.
120+
/// - metrics: The metrics factory to use.
121121
/// - Throws: If the file cannot be read or parsed, or if the JSON structure is invalid.
122122
internal init(
123123
filePath: FilePath,
124124
pollInterval: Duration,
125125
bytesDecoder: some ConfigBytesFromStringDecoder,
126126
secretsSpecifier: SecretsSpecifier<String, any Sendable>,
127127
fileSystem: some CommonProviderFileSystem,
128-
logger: Logger?,
129-
metrics: (any MetricsFactory)?
128+
logger: Logger,
129+
metrics: any MetricsFactory
130130
) async throws {
131131
self.core = try await ReloadingFileProviderCore(
132132
filePath: filePath,
@@ -189,8 +189,8 @@ public final class ReloadingJSONProvider: Sendable {
189189
config: ConfigReader,
190190
bytesDecoder: some ConfigBytesFromStringDecoder = .base64,
191191
secretsSpecifier: SecretsSpecifier<String, any Sendable> = .none,
192-
logger: Logger? = nil,
193-
metrics: (any MetricsFactory)? = nil
192+
logger: Logger = Logger(label: "ReloadingJSONProvider"),
193+
metrics: any MetricsFactory = MetricsSystem.factory
194194
) async throws {
195195
try await self.init(
196196
filePath: config.requiredString(forKey: "filePath", as: FilePath.self),

Sources/Configuration/Providers/YAML/ReloadingYAMLProvider.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,16 @@ public final class ReloadingYAMLProvider: Sendable {
9292
/// - pollInterval: The interval between file modification checks. Defaults to 15 seconds.
9393
/// - bytesDecoder: The decoder used to convert string values to byte arrays.
9494
/// - secretsSpecifier: Specifies which configuration values should be treated as secrets.
95-
/// - logger: The logger instance to use, or nil to create a default one.
96-
/// - metrics: The metrics factory to use, or nil to use a no-op implementation.
95+
/// - logger: The logger instance to use.
96+
/// - metrics: The metrics factory to use.
9797
/// - Throws: If the file cannot be read or parsed, or if the YAML structure is invalid.
9898
public convenience init(
9999
filePath: FilePath,
100100
pollInterval: Duration = .seconds(15),
101101
bytesDecoder: some ConfigBytesFromStringDecoder = .base64,
102102
secretsSpecifier: SecretsSpecifier<String, Void> = .none,
103-
logger: Logger? = nil,
104-
metrics: (any MetricsFactory)? = nil
103+
logger: Logger = Logger(label: "ReloadingYAMLProvider"),
104+
metrics: any MetricsFactory = MetricsSystem.factory
105105
) async throws {
106106
try await self.init(
107107
filePath: filePath,
@@ -121,17 +121,17 @@ public final class ReloadingYAMLProvider: Sendable {
121121
/// - bytesDecoder: A decoder of bytes from a string.
122122
/// - secretsSpecifier: A secrets specifier in case some of the values should be treated as secret.
123123
/// - fileSystem: The underlying file system.
124-
/// - logger: The logger instance to use, or nil to create a default one.
125-
/// - metrics: The metrics factory to use, or nil to use a no-op implementation.
124+
/// - logger: The logger instance to use.
125+
/// - metrics: The metrics factory to use.
126126
/// - Throws: If the file cannot be read or parsed, or if the YAML structure is invalid.
127127
internal init(
128128
filePath: FilePath,
129129
pollInterval: Duration,
130130
bytesDecoder: some ConfigBytesFromStringDecoder,
131131
secretsSpecifier: SecretsSpecifier<String, Void>,
132132
fileSystem: some CommonProviderFileSystem,
133-
logger: Logger?,
134-
metrics: (any MetricsFactory)?
133+
logger: Logger,
134+
metrics: any MetricsFactory
135135
) async throws {
136136
self.core = try await ReloadingFileProviderCore(
137137
filePath: filePath,
@@ -186,15 +186,15 @@ public final class ReloadingYAMLProvider: Sendable {
186186
/// - config: The configuration reader containing the file path.
187187
/// - bytesDecoder: The decoder used to convert string values to byte arrays.
188188
/// - secretsSpecifier: Specifies which configuration values should be treated as secrets.
189-
/// - logger: The logger instance to use, or nil to create a default one.
190-
/// - metrics: The metrics factory to use, or nil to use a no-op implementation.
189+
/// - logger: The logger instance to use.
190+
/// - metrics: The metrics factory to use.
191191
/// - Throws: If the file path is missing, or if the file cannot be read or parsed.
192192
public convenience init(
193193
config: ConfigReader,
194194
bytesDecoder: some ConfigBytesFromStringDecoder = .base64,
195195
secretsSpecifier: SecretsSpecifier<String, Void> = .none,
196-
logger: Logger? = nil,
197-
metrics: (any MetricsFactory)? = nil
196+
logger: Logger = Logger(label: "ReloadingYAMLProvider"),
197+
metrics: any MetricsFactory = MetricsSystem.factory
198198
) async throws {
199199
try await self.init(
200200
filePath: config.requiredString(forKey: "filePath", as: FilePath.self),

Tests/ConfigurationTests/ReloadingFileProviderCoreTests.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import ConfigurationTestingInternal
2020
import Foundation
2121
import ConfigurationTesting
2222
import Logging
23+
import Metrics
2324
import ServiceLifecycle
2425
import Synchronization
2526
import SystemPackage
@@ -97,7 +98,7 @@ private func withTestProvider<R>(
9798
providerName: "TestProvider",
9899
fileSystem: fileSystem,
99100
logger: .noop,
100-
metrics: nil,
101+
metrics: NOOPMetricsHandler.instance,
101102
createSnapshot: { data in
102103
try TestSnapshot(contents: String(decoding: data, as: UTF8.self))
103104
}
@@ -155,7 +156,7 @@ struct CoreTests {
155156
providerName: "TestProvider",
156157
fileSystem: fileSystem,
157158
logger: .noop,
158-
metrics: nil,
159+
metrics: NOOPMetricsHandler.instance,
159160
createSnapshot: { data in
160161
try TestSnapshot(contents: String(decoding: data, as: UTF8.self))
161162
}

0 commit comments

Comments
 (0)