swift-log icon indicating copy to clipboard operation
swift-log copied to clipboard

RFC: Add capability to configure loggers inline

Open Mordil opened this issue 2 years ago • 1 comments

Adds initializers and methods to create Logger instances with metadata inline.

Motivation:

Frequently it's needed to create copies of loggers, or a new logger, with attached metadata or specific log levels, but the current method requires first creating an instance, as a var, and then configuring the instance.

This leaves you to have a mutable value existing in the scope even if you don't want to.

This particularly has issues with async code when capturing the instance in a Task because it's non-isolated

var logger = Logger(label: "\(#function)")
logger[metadataKey: metadataKey] = "original"

Task {
    logger.trace("won't work")
       // ^^^^^ Reference to captured var 'logger' in concurrently-executing code
 }

The best way to get around this is either

// 1 immediately invoked closure
let logger = {
    let inner = Logger(...)
    // configuration
    return inner
}()

// 2 variable rebinding
let retainedLogger = logger
Task {
    retainedLogger.trace("will work")
}

// 3 explicit capture
Task { [logger] in
    logger.trace("will also work")
}

Modifications:

  • Add: makeCopy(with:mergePolicy:) to allow just setting inline the metadata you want the new instance to have, with control on how to merge with existing metadata keys
  • Add: makeCopy(_:) which passes an inout reference to the new instance, allowing you to set more options such as logLevel as part of creation
  • Add: init(label:metadata:) that allows creation of instances directly inline that directly sets the metadata
  • Add: init(label:_:) that allows creation of instances with a reference to the object for inline configuration much like makeCopy(_:)

Result:

Developers will now be able to make Logger instances, or "children" copies, directly inline with full control over the value's mutability - making it safe to send across Task boundaries

let logger = Logger(label: "myLabel") {
    $0.logLevel = .info
    $0[metadataKey: "my_key"] = "my value"
}

Task {
    logger.info("this works")
}

Mordil avatar Dec 22 '22 04:12 Mordil

Can one of the admins verify this patch?

swift-server-bot avatar Dec 22 '22 04:12 swift-server-bot