Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix logger to only initialize it once #282

Merged
merged 26 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ awsCIoPlatformExcludes.append("source/s2n")
/// aws-c-checksums
//////////////////////////////////////////////////////////////////////
var awsCChecksumsExcludes = [
"bin",
"CMakeLists.txt",
"LICENSE",
"builder.json",
Expand Down
11 changes: 9 additions & 2 deletions Source/AwsCommonRuntimeKit/crt/CommonRuntimeError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,20 @@ public struct CRTError: Equatable {
public let message: String
public let name: String

public init<T: BinaryInteger>(code: T) {
public init<T: BinaryInteger>(code: T, context: String? = nil) {
if code > INT32_MAX || code <= 0 {
self.code = Int32(AWS_ERROR_UNKNOWN.rawValue)
} else {
self.code = Int32(code)
}
self.message = String(cString: aws_error_str(self.code))
var message = String(cString: aws_error_str(self.code))
if let context {
if message.last != "." {
message += "."
}
message += " " + context
}
self.message = message
self.name = String(cString: aws_error_name(self.code))
}

Expand Down
64 changes: 41 additions & 23 deletions Source/AwsCommonRuntimeKit/crt/Logger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,56 @@
// SPDX-License-Identifier: Apache-2.0.

import AwsCCommon
var logger: aws_logger?
import Foundation

public enum LogTarget {
case standardOutput
case standardError
case filePath(String)
}

public struct Logger {
public static func initialize(pipe: UnsafeMutablePointer<FILE>?, level: LogLevel) {
// Clean up the logger if it was previously initialized
if var logger = logger {
aws_logger_clean_up(&logger)
aws_logger_set(nil)
private static var logger: aws_logger?
private static let lock = NSLock()

/// Initializes the CRT logger based on the specified log target and log level. The CRT logger must be only initialized once in your application. Initializing the logger multiple times is not supported.
/// - Parameters:
/// - target: The logging target, which can be standard output, standard error, or a custom file path.
/// - level: The logging level, represented by the `LogLevel` enum.
/// - Throws: CommonRunTimeError.crtException
public static func initialize(target: LogTarget, level: LogLevel) throws {
lock.lock()
defer { lock.unlock() }

// Check if the logger is already initialized
guard logger == nil else {
throw CommonRunTimeError.crtError(CRTError(
code: AWS_ERROR_UNSUPPORTED_OPERATION.rawValue,
context: "Initializing the CRT Logger multiple times is not supported."))
}

// Initialize the logger
logger = aws_logger()
var options = aws_logger_standard_options()
options.level = level.rawValue
options.file = pipe
aws_logger_init_standard(&logger!, allocator.rawValue, &options)
aws_logger_set(&logger!)
}

public static func initilize(filePath: String, level: LogLevel) {
// Clean up the logger if it was previously initialized
if var logger = logger {
aws_logger_clean_up(&logger)
aws_logger_set(nil)
}
logger = aws_logger()

filePath.withCString { cFilePath in
var options = aws_logger_standard_options()
options.level = level.rawValue
options.filename = cFilePath
// Set options based on the logging target
switch target {
case .standardOutput:
options.file = stdout
aws_logger_init_standard(&logger!, allocator.rawValue, &options)
aws_logger_set(&logger!)
case .standardError:
options.file = stderr
aws_logger_init_standard(&logger!, allocator.rawValue, &options)
case .filePath(let filePath):
filePath.withCString { cFilePath in
options.filename = cFilePath
aws_logger_init_standard(&logger!, allocator.rawValue, &options)
}
}

// Initialize and set the logger
aws_logger_set(&logger!)
}
}

Expand Down
4 changes: 2 additions & 2 deletions Source/Elasticurl/Elasticurl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -220,10 +220,10 @@ struct Elasticurl {
createOutputFile()
if let traceFile = context.traceFile {
print("enable logging with trace file")
Logger.initilize(filePath: traceFile, level: context.logLevel)
try? Logger.initialize(target: .filePath(traceFile), level: context.logLevel)
} else {
print("enable logging with stdout")
Logger.initialize(pipe: stdout, level: context.logLevel)
try? Logger.initialize(target: .standardOutput, level: context.logLevel)
}

await run()
Expand Down
4 changes: 2 additions & 2 deletions Test/AwsCommonRuntimeKitTests/XCBaseTestCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import AwsCCommon

class XCBaseTestCase: XCTestCase {
internal let tracingAllocator = TracingAllocator(tracingStacksOf: allocator)

override func setUp() {
super.setUp()
// XCode currently lacks a way to enable logs exclusively for failed tests only.
// To prevent log spamming, we use `error` log level to only print error message.
// We should update this once a more efficient log processing method becomes available.
Logger.initialize(pipe: stdout, level: .error)
try? Logger.initialize(target: .standardOutput, level: .error)

// Override the allocator with tracing allocator
allocator = tracingAllocator.rawValue
Expand Down
2 changes: 1 addition & 1 deletion aws-common-runtime/aws-c-cal
2 changes: 1 addition & 1 deletion aws-common-runtime/s2n
Submodule s2n updated 259 files
Loading