Skip to content

Commit

Permalink
Add OTelLogHandler that sends OTelLogEntry to an OTelLogEntryProcessor
Browse files Browse the repository at this point in the history
  • Loading branch information
Joannis authored and slashmo committed Mar 27, 2024
1 parent 0735233 commit aaa789d
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 0 deletions.
22 changes: 22 additions & 0 deletions Sources/OTel/Logging/OTLPLogEntryDataModel.swift
@@ -0,0 +1,22 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift OTel open source project
//
// Copyright (c) 2024 Moritz Lang and the Swift OTel project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

import Logging

@_spi(Logging)
public struct OTelLogEntry: Equatable, Sendable {
public let body: String
public let level: Logger.Level
public let metadata: Logger.Metadata?
public let timeNanosecondsSinceEpoch: UInt64
}
62 changes: 62 additions & 0 deletions Sources/OTel/Logging/OTelLogHandler.swift
@@ -0,0 +1,62 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift OTel open source project
//
// Copyright (c) 2024 Moritz Lang and the Swift OTel project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

import AsyncAlgorithms
import Logging
import NIOConcurrencyHelpers
import ServiceLifecycle
import Logging
import Tracing

@_spi(Logging)
public struct OTelLogHandler: Sendable, LogHandler {
public var metadata: Logging.Logger.Metadata
public var logLevel: Logging.Logger.Level
private let processor: any OTelLogEntryProcessor

public init(
processor: any OTelLogEntryProcessor,
logLevel: Logger.Level,
metadata: Logger.Metadata = [:]
) {
self.processor = processor
self.logLevel = logLevel
self.metadata = metadata
}

public subscript(metadataKey key: String) -> Logging.Logger.Metadata.Value? {
get { metadata[key] }
set { metadata[key] = newValue }
}

public func log(
level: Logger.Level,
message: Logger.Message,
metadata: Logger.Metadata?,
source: String,
file: String,
function: String,
line: UInt
) {
let instant = DefaultTracerClock().now

let message = OTelLogEntry(
body: message.description,
level: level,
metadata: metadata,
timeNanosecondsSinceEpoch: instant.nanosecondsSinceEpoch
)

processor.onLog(message)
}
}
31 changes: 31 additions & 0 deletions Sources/OTel/Logging/Processing/OTelLogEntryProcessor.swift
@@ -0,0 +1,31 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift OTel open source project
//
// Copyright (c) 2024 Moritz Lang and the Swift OTel project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

import ServiceLifecycle
import ServiceContextModule

/// Log processors allow for processing logs throughout their lifetime via ``onStart(_:parentContext:)`` and ``onEnd(_:)`` calls.
/// Usually, log processors will forward logs to a configurable ``OTelLogEntryExporter``.
///
/// [OpenTelemetry specification: LogRecord processor](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/logs/sdk.md#logrecordprocessor)
///
/// ### Implementation Notes
///
/// On shutdown, processors forwarding logs to an ``OTelLogEntryExporter`` MUST shutdown that exporter.
@_spi(Logging)
public protocol OTelLogEntryProcessor: Service & Sendable {
func onLog(_ log: OTelLogEntry)

/// Force log processors that batch logs to flush immediately.
func forceFlush() async throws
}
40 changes: 40 additions & 0 deletions Sources/OTel/Logging/Processing/OTelNoOpLogEntryProcessor.swift
@@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift OTel open source project
//
// Copyright (c) 2024 Moritz Lang and the Swift OTel project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

import ServiceContextModule

/// A log entry processor that ignores all operations, used when no logs should be processed.
@_spi(Logging)
public struct OTelNoOpLogEntryProcessor: OTelLogEntryProcessor, CustomStringConvertible {
public let description = "OTelNoOpLogEntryProcessor"

private let stream: AsyncStream<Void>
private let continuation: AsyncStream<Void>.Continuation

/// Initialize a no-op log entry processor.
public init() {
(stream, continuation) = AsyncStream.makeStream()
}

public func run() async {
for await _ in stream.cancelOnGracefulShutdown() {}
}

public func onLog(_ log: OTelLogEntry) {
// no-op
}

public func forceFlush() async throws {
// no-op
}
}

0 comments on commit aaa789d

Please sign in to comment.