Skip to content

Commit

Permalink
Merge branch 'main' into jbe/account_id_config
Browse files Browse the repository at this point in the history
  • Loading branch information
jbelkins committed Dec 12, 2024
2 parents 0c45689 + 2b7c80c commit 04dda1a
Show file tree
Hide file tree
Showing 13 changed files with 143 additions and 90 deletions.
2 changes: 1 addition & 1 deletion Package.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.100.0
0.101.0
2 changes: 1 addition & 1 deletion Package.version.next
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.101.0
0.102.0
12 changes: 4 additions & 8 deletions Sources/ClientRuntime/Networking/Http/CRT/SDKDefaultIO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,11 @@ public final class SDKDefaultIO: @unchecked Sendable {
/// Provide singleton access since we want to share and re-use the instance properties
public static let shared = SDKDefaultIO()

/// The setter for changing log level of SDKDefaultIO logger.
/// If any log level other than the default log level of `.none` is desired,
/// this setter needs to be called as the first thing in the program.
/// The public setter for setting log level of CRT logger.
///
/// If any log level other than the default log level of `.none` is desired, this setter **MUST** be called before accessing the `SDKDefaultIO.shared` static field.
public static func setLogLevel(level: LogLevel) {
do {
try Logger.initialize(target: .standardOutput, level: level)
} catch {
failOnLogger()
}
SDKDefaultIO.setupLogger(level: level)
}

private init() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// SPDX-License-Identifier: Apache-2.0
//

/// Additional logging opt-in for request / response flow. For each selected option other than `.none`, the additional info gets logged at `.debug` level by the `LoggingMiddleware`.
public enum ClientLogMode {
case none
case request
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import AwsCommonRuntimeKit

/// Extension for CRT's LogLevel enum
extension LogLevel {
public var stringValue: String {
switch self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import Logging

/// Implement this protocol and add an instance of the implementation to `SDKLoggingSystem` to use custom log handlers.
public protocol SDKLogHandlerFactory {
var label: String { get }
func construct(label: String) -> LogHandler
Expand Down
1 change: 1 addition & 0 deletions Sources/ClientRuntime/Telemetry/Logging/SDKLogLevel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import Logging

/// Wrapper for Logger.Level; used by SDKLoggingSystem.
public enum SDKLogLevel: String, Codable, CaseIterable {
case trace
case debug
Expand Down
32 changes: 20 additions & 12 deletions Sources/ClientRuntime/Telemetry/Logging/SDKLoggingSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,35 @@

import Logging

/// Use this to turn SDK logging on.
public actor SDKLoggingSystem {
private var isInitialized = false
private var factories: [String: SDKLogHandlerFactory] = [:]
private var logHandlerFactories: [String: SDKLogHandlerFactory] = [:]

public init() {}

/// Adds custom log handler factory to `this.logHandlerFactories`.
///
/// The added log handler factory will be dedicated log handler for any logger with identical label.
public func add(logHandlerFactory: SDKLogHandlerFactory) {
let label = logHandlerFactory.label
factories[label] = logHandlerFactory
logHandlerFactories[logHandlerFactory.label] = logHandlerFactory
}

/// Initializes the logging handler factory for the SDK.
/// The default behavior is to log messages at `.error` or more severe levels.
///
/// The handler factory closure first checks if there exists a custom handler factory in `this.logHandlerFactories` with the same label as the label given to logger initializer. If it exists, then that factory gets used to create the log handler.
///
/// If no custom handler factory is found for the given label, the factory closure creates and returns a `StreamLogHandler` with minimum log level set to `logLevel`.
///
/// Loggers output log only if the log level of the message is equal to or more severe than the underlying log handler's log level. E.g., `logger.info(...)` executes only if the underlying log handler's log level is `.info`, `.debug`, or `.trace`. It does not execute if the underlying log handler's minimum log level is any one of the following levels that are more severe than `.info`: `.notice`, `.warning`, `error`, `critical`.
///
/// - parameters:
/// - logLevel: The minimum log level to use for the log handler if no custom log handler factory was found. Default is `.error`.
public func initialize(defaultLogLevel: SDKLogLevel = .error) async {
if isInitialized { return } else { isInitialized = true }
let ptr = factories
LoggingSystem.bootstrap { label in
if let factory = ptr[label] {
LoggingSystem.bootstrap { [logHandlerFactories] label in
if let factory = logHandlerFactories[label] {
return factory.construct(label: label)
}
var handler = StreamLogHandler.standardOutput(label: label)
Expand All @@ -32,11 +45,6 @@ public actor SDKLoggingSystem {
}

public func initialize(logLevel: SDKLogLevel) async {
if isInitialized { return } else { isInitialized = true }
LoggingSystem.bootstrap { label in
var handler = StreamLogHandler.standardOutput(label: label)
handler.logLevel = logLevel.toLoggerType()
return handler
}
await self.initialize(defaultLogLevel: logLevel)
}
}
105 changes: 70 additions & 35 deletions Sources/Smithy/Logging/LogAgent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ public protocol LogAgent {
/// name of the struct or class where the logger was instantiated from
var name: String { get }

/// Get or set the configured log level.
var level: LogAgentLevel { get set }

/// This method is called when a `LogAgent` must emit a log message.
///
/// - parameters:
Expand All @@ -31,76 +28,114 @@ public protocol LogAgent {
line: UInt)
}

public enum LogAgentLevel: String, Codable, CaseIterable {
case trace
case debug
case info
case warn
case error
case fatal
}

/// Convenience wrapper functions that call `self.log()` with corresponding log level.
public extension LogAgent {
/// Use for messages that are typically seen during tracing.
func trace(
_ message: @autoclosure() -> String,
file: String = #fileID,
function: String = #function,
line: UInt = #line
) {
self.log(level: .trace,
message: message(),
metadata: nil,
source: currentModule(fileID: file),
file: file,
function: function,
line: line)
}

/// Log a message passing with the `.info` log level.
func info(_ message: String, file: String = #fileID, function: String = #function, line: UInt = #line) {
self.log(level: .info,
message: message,
/// Use for messages that are typically seen during debugging.
func debug(
_ message: @autoclosure() -> String,
file: String = #fileID,
function: String = #function,
line: UInt = #line
) {
self.log(level: .debug,
message: message(),
metadata: nil,
source: currentModule(fileID: file),
file: file,
function: function,
line: line)
}

/// Log a message passing with the `LogLevel.warn` log level.
func warn(_ message: String, file: String = #fileID, function: String = #function, line: UInt = #line) {
self.log(level: .warn,
message: message,
/// Use for informational messages.
func info(
_ message: @autoclosure() -> String,
file: String = #fileID,
function: String = #function,
line: UInt = #line
) {
self.log(level: .info,
message: message(),
metadata: nil,
source: currentModule(fileID: file),
file: file,
function: function,
line: line)
}

/// Log a message passing with the `.debug` log level.
func debug(_ message: String, file: String = #fileID, function: String = #function, line: UInt = #line) {
self.log(level: .debug,
message: message,
/// Use for non-error messages that may need special attention.
func notice(
_ message: @autoclosure() -> String,
file: String = #fileID,
function: String = #function,
line: UInt = #line
) {
self.log(level: .notice,
message: message(),
metadata: nil,
source: currentModule(fileID: file),
file: file,
function: function,
line: line)
}

/// Log a message passing with the `.error` log level.
func error(_ message: String, file: String = #fileID, function: String = #function, line: UInt = #line) {
self.log(level: .error,
message: message,
/// Use for non-error messages that are more severe than `.notice`.
func warn(
_ message: @autoclosure() -> String,
file: String = #fileID,
function: String = #function,
line: UInt = #line
) {
self.log(level: .warn,
message: message(),
metadata: nil,
source: currentModule(fileID: file),
file: file,
function: function,
line: line)
}

/// Log a message passing with the `.trace` log level.
func trace(_ message: String, file: String = #fileID, function: String = #function, line: UInt = #line) {
self.log(level: .trace,
message: message,
/// Use for errors.
func error(
_ message: @autoclosure() -> String,
file: String = #fileID,
function: String = #function,
line: UInt = #line
) {
self.log(level: .error,
message: message(),
metadata: nil,
source: currentModule(fileID: file),
file: file,
function: function,
line: line)
}

/// Log a message passing with the `.fatal` log level.
func fatal(_ message: String, file: String = #fileID, function: String = #function, line: UInt = #line) {
/// Appropriate for critical error conditions that usually require immediate
/// attention.
func fatal(
_ message: @autoclosure() -> String,
file: String = #fileID,
function: String = #function,
line: UInt = #line
) {
self.log(level: .fatal,
message: message,
message: message(),
metadata: nil,
source: currentModule(fileID: file),
file: file,
Expand Down
38 changes: 38 additions & 0 deletions Sources/Smithy/Logging/LogAgentLevel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Logging

/// Wrapper for Logger.Level; used by LogAgent and SwiftLogger.
public enum LogAgentLevel: String, Codable, CaseIterable {
case trace
case debug
case info
case notice
case warn
case error
case fatal

func toLoggerLevel() -> Logger.Level {
switch self {
case .trace:
return .trace
case .debug:
return .debug
case .info:
return .info
case .notice:
return .notice
case .warn:
return .warning
case .error:
return .error
case .fatal:
return .critical
}
}
}
31 changes: 3 additions & 28 deletions Sources/Smithy/Logging/SwiftLog+LogAgent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,22 @@
import Logging

public struct SwiftLogger: LogAgent {
public var level: LogAgentLevel

private let logger: Logger
private let label: String

public init(label: String) {
self.label = label
self.logger = Logger(label: label)
self.level = LogAgentLevel.info
}

@available(*, deprecated, message: "This API is deprecated. Use init(label:) instead.")
public init(label: String, logLevel: LogAgentLevel) {
self.label = label
self.logger = Logger(label: label)
self.level = logLevel
self.init(label: label)
}

// This initializer is currently only used in tests, to inject a mock LogHandler.
init(label: String, logLevel: LogAgentLevel, factory: (String) -> any LogHandler) {
init(label: String, factory: (String) -> any LogHandler) {
self.label = label
self.level = logLevel
self.logger = Logger(label: label, factory: factory)
}

Expand Down Expand Up @@ -56,23 +51,3 @@ public struct SwiftLogger: LogAgent {
)
}
}

extension LogAgentLevel {

func toLoggerLevel() -> Logger.Level {
switch self {
case .trace:
return .trace
case .debug:
return .debug
case .info:
return .info
case .warn:
return .warning
case .error:
return .error
case .fatal:
return .critical
}
}
}
4 changes: 2 additions & 2 deletions Tests/ClientRuntimeTests/LoggingTests/SwiftLoggerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ final class SwiftLoggerTests: XCTestCase {

private func logsLeveledMessage(
logLevel: Logger.Level,
loggerBlock: (SwiftLogger) -> (String, String, String, UInt) -> Void,
loggerBlock: (SwiftLogger) -> (@autoclosure() -> String, String, String, UInt) -> Void,
testFile: StaticString = #filePath,
testLine: UInt = #line
) throws {
Expand All @@ -53,7 +53,7 @@ final class SwiftLoggerTests: XCTestCase {
// Create a TestLogHandler, then create a SwiftLogger (the test subject)
// with it.
var logHandler: TestLogHandler!
let subject = SwiftLogger(label: "Test", logLevel: .trace, factory: { label in
let subject = SwiftLogger(label: "Test", factory: { label in
logHandler = TestLogHandler(label: label)
return logHandler
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,9 @@ private class TestLogger: LogAgent {

var messages: [(level: LogAgentLevel, message: String)] = []

var level: LogAgentLevel

init(name: String = "Test", messages: [(level: LogAgentLevel, message: String)] = [], level: LogAgentLevel = .info) {
self.name = name
self.messages = messages
self.level = level
}

func log(level: LogAgentLevel = .info, message: @autoclosure () -> String, metadata: @autoclosure () -> [String : String]? = nil, source: @autoclosure () -> String = "ChecksumUnitTests", file: String = #file, function: String = #function, line: UInt = #line) {
Expand Down

0 comments on commit 04dda1a

Please sign in to comment.