Browse Source

Add a static-source Logger (#1165)

Motivation:

swift-log includes a `source` field which -- in most cases -- should be
the name of the module. Currently swift-log parses the `#file` to use
the directory containing the file in the hope that it is the module
name.

In our tests we have a tear down step which validates that all caputred
logs have 'GRPC' as their source. However, this requires manually
providing the source in a bunch of places, that's a bit of a pain and
only validates the logs we emit.

Modifications:

- Add an internal `GRPCLogger` which wraps a `Logger` providing only
  `trace` and `debug` (for now) and always sets the source to `GRPC`.

Result:

It's harder to get the source wrong.
George Barnett 4 years ago
parent
commit
66f74fc826
2 changed files with 112 additions and 0 deletions
  1. 74 0
      Sources/GRPC/GRPCLogger.swift
  2. 38 0
      Tests/GRPCTests/GRPCLoggerTests.swift

+ 74 - 0
Sources/GRPC/GRPCLogger.swift

@@ -0,0 +1,74 @@
+/*
+ * Copyright 2021, gRPC Authors All rights reserved.
+ *
+ * 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 Logging
+
+/// Wraps `Logger` to always provide the source as "GRPC".
+///
+/// See https://github.com/apple/swift-log/issues/145 for rationale.
+internal struct GRPCLogger {
+  private var logger: Logger
+
+  internal var unwrapped: Logger {
+    return self.logger
+  }
+
+  internal init(wrapping logger: Logger) {
+    self.logger = logger
+  }
+
+  internal subscript(metadataKey metadataKey: String) -> Logger.Metadata.Value? {
+    get {
+      return self.logger[metadataKey: metadataKey]
+    }
+    set {
+      self.logger[metadataKey: metadataKey] = newValue
+    }
+  }
+
+  internal func trace(
+    _ message: @autoclosure () -> Logger.Message,
+    metadata: @autoclosure () -> Logger.Metadata? = nil,
+    file: String = #file,
+    function: String = #function,
+    line: UInt = #line
+  ) {
+    self.logger.trace(
+      message(),
+      metadata: metadata(),
+      source: "GRPC",
+      file: file,
+      function: function,
+      line: line
+    )
+  }
+
+  internal func debug(
+    _ message: @autoclosure () -> Logger.Message,
+    metadata: @autoclosure () -> Logger.Metadata? = nil,
+    file: String = #file,
+    function: String = #function,
+    line: UInt = #line
+  ) {
+    self.logger.debug(
+      message(),
+      metadata: metadata(),
+      source: "GRPC",
+      file: file,
+      function: function,
+      line: line
+    )
+  }
+}

+ 38 - 0
Tests/GRPCTests/GRPCLoggerTests.swift

@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021, gRPC Authors All rights reserved.
+ *
+ * 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.
+ */
+@testable import GRPC
+import Logging
+import XCTest
+
+final class GRPCLoggerTests: GRPCTestCase {
+  func testLogSourceIsGRPC() {
+    let recorder = CapturingLogHandlerFactory(printWhenCaptured: false)
+    let logger = Logger(label: "io.grpc.testing", factory: recorder.make(_:))
+
+    var gRPCLogger = GRPCLogger(wrapping: logger)
+    gRPCLogger[metadataKey: "foo"] = "bar"
+
+    gRPCLogger.debug("foo")
+    gRPCLogger.trace("bar")
+
+    let logs = recorder.clearCapturedLogs()
+    XCTAssertEqual(logs.count, 2)
+    for log in logs {
+      XCTAssertEqual(log.source, "GRPC")
+      XCTAssertEqual(gRPCLogger[metadataKey: "foo"], "bar")
+    }
+  }
+}