Skip to content

Commit cc255c6

Browse files
committed
Change dependency to intercept at MetricsSystem level
1 parent 11d73cc commit cc255c6

File tree

5 files changed

+42
-28
lines changed

5 files changed

+42
-28
lines changed

Sources/App/Core/AppMetrics.swift

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,13 @@ enum AppMetrics {
141141
extension AppMetrics {
142142

143143
static func counter<V: Numeric>(_ name: String) -> PromCounter<V>? {
144-
@Dependency(\.prometheus) var prometheus
145-
return prometheus?.createCounter(forType: V.self, named: name)
144+
@Dependency(\.metricsSystem.prometheus) var prometheus
145+
return try? prometheus().createCounter(forType: V.self, named: name)
146146
}
147147

148148
static func gauge<V: DoubleRepresentable>(_ name: String) -> PromGauge<V>? {
149-
@Dependency(\.prometheus) var prometheus
150-
return prometheus?.createGauge(forType: V.self, named: name)
149+
@Dependency(\.metricsSystem.prometheus) var prometheus
150+
return try? prometheus().createGauge(forType: V.self, named: name)
151151
}
152152

153153
}
@@ -162,19 +162,15 @@ extension AppMetrics {
162162
static func push(client: Client, jobName: String) async throws {
163163
@Dependency(\.environment) var environment
164164
@Dependency(\.logger) var logger
165-
@Dependency(\.prometheus) var prometheus
166-
167-
guard let prometheus else {
168-
throw AppError.genericError(nil, "Prometheus client unavailable (nil)")
169-
}
165+
@Dependency(\.metricsSystem.prometheus) var prometheus
170166

171167
guard let pushGatewayUrl = environment.metricsPushGatewayUrl() else {
172168
throw AppError.envVariableNotSet("METRICS_PUSHGATEWAY_URL")
173169
}
174170
let url = URI(string: "\(pushGatewayUrl)/metrics/job/\(jobName)")
175171

176172
do {
177-
let metrics: String = await prometheus.collect()
173+
let metrics: String = try await prometheus().collect()
178174
_ = try await client.post(url) { req in
179175
// append "\n" to avoid
180176
// text format parsing error in line 4: unexpected end of input stream

Sources/App/Core/Dependencies/AppMetricsClient.swift renamed to Sources/App/Core/Dependencies/MetricsSystemClient.swift

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,17 @@ import Synchronization
1818
@preconcurrency import Prometheus
1919

2020

21-
enum AppMetricsClient {
21+
struct MetricsSystemClient {
22+
var prometheus: @Sendable () throws -> PrometheusClient
23+
}
24+
25+
26+
extension MetricsSystemClient {
2227
private static let initialized = Mutex(false)
2328

24-
static func bootstrap() {
25-
guard !initialized.withLock({ $0 }) else { return }
26-
initialized.withLock {
29+
func bootstrap() {
30+
guard !Self.initialized.withLock({ $0 }) else { return }
31+
Self.initialized.withLock {
2732
let client = PrometheusClient()
2833
MetricsSystem.bootstrap(PrometheusMetricsFactory(client: client))
2934
$0 = true
@@ -32,23 +37,33 @@ enum AppMetricsClient {
3237
}
3338

3439

35-
extension AppMetricsClient: DependencyKey {
36-
static var liveValue: PrometheusClient? {
37-
try? MetricsSystem.prometheus()
40+
extension MetricsSystemClient: DependencyKey {
41+
static var liveValue: Self {
42+
.init(prometheus: { try MetricsSystem.prometheus() })
3843
}
3944
}
4045

4146

42-
extension AppMetricsClient: TestDependencyKey {
43-
static var testValue: PrometheusClient? {
44-
unimplemented("testValue"); return nil
47+
extension MetricsSystemClient: TestDependencyKey {
48+
static var testValue: Self {
49+
.init(prometheus: { unimplemented("testValue"); return .init() })
4550
}
4651
}
4752

4853

4954
extension DependencyValues {
50-
public var prometheus: PrometheusClient? {
51-
get { self[AppMetricsClient.self] }
52-
set { self[AppMetricsClient.self] = newValue }
55+
var metricsSystem: MetricsSystemClient {
56+
get { self[MetricsSystemClient.self] }
57+
set { self[MetricsSystemClient.self] = newValue }
58+
}
59+
}
60+
61+
62+
#if DEBUG
63+
extension MetricsSystemClient {
64+
static var mock: Self {
65+
let prometheus = PrometheusClient()
66+
return .init(prometheus: { prometheus })
5367
}
5468
}
69+
#endif

Sources/App/configure.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,8 @@ public func configure(_ app: Application, databasePort: Int? = nil) async throws
365365
try routes(app)
366366

367367
// bootstrap app metrics
368-
AppMetricsClient.bootstrap()
368+
@Dependency(\.metricsSystem) var metricsSystem
369+
metricsSystem.bootstrap()
369370

370371
return host
371372
}

Sources/App/routes.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,8 @@ func routes(_ app: Application) throws {
211211

212212
do { // Metrics
213213
app.get("metrics") { req -> String in
214-
@Dependency(\.prometheus) var prometheus
215-
return await prometheus?.collect() ?? ""
214+
@Dependency(\.metricsSystem.prometheus) var prometheus
215+
return try await prometheus().collect()
216216
}
217217
}
218218
}

Tests/AppTests/AllTests.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
import Testing
15+
@testable import App
16+
1617
import Dependencies
18+
import Testing
1719

1820

1921
@Suite(
2022
.dependency(\.date.now, .t0),
21-
.dependency(\.prometheus, .init())
23+
.dependency(\.metricsSystem, .mock)
2224
) struct AllTests { }
2325

2426

0 commit comments

Comments
 (0)