Skip to content

Commit

Permalink
Add back accidentally removed API (#152)
Browse files Browse the repository at this point in the history
Motivation:

- When `source:` was added in #135, the API was accidentally broken
  despite source compatability.

Modifications:

- Add back source-less API calls which defer to the decls with source.
- Note we can't deprecate the calls we're adding back:
  `log.info("some message")` refers to the implementation we're adding
  back rather and would therefore require users to explicitly specify a source
  to suppress the deprecation warning message.

Result:

- API is no longer broken.

Co-authored-by: Konrad `ktoso` Malawski <ktoso@apple.com>
  • Loading branch information
glbrntt and ktoso authored Feb 22, 2021
1 parent b544051 commit 12d3a86
Show file tree
Hide file tree
Showing 3 changed files with 239 additions and 2 deletions.
171 changes: 171 additions & 0 deletions Sources/Logging/Logging.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,29 @@ extension Logger {
}
}

/// Log a message passing the log level as a parameter.
///
/// If the `logLevel` passed to this method is more severe than the `Logger`'s `logLevel`, it will be logged,
/// otherwise nothing will happen.
///
/// - parameters:
/// - level: The log level to log `message` at. For the available log levels, see `Logger.Level`.
/// - message: The message to be logged. `message` can be used with any string interpolation literal.
/// - metadata: One-off metadata to attach to this log message.
/// - file: The file this log message originates from (there's usually no need to pass it explicitly as it
/// defaults to `#file`).
/// - function: The function this log message originates from (there's usually no need to pass it explicitly as
/// it defaults to `#function`).
/// - line: The line this log message originates from (there's usually no need to pass it explicitly as it
/// defaults to `#line`).
@inlinable
public func log(level: Logger.Level,
_ message: @autoclosure () -> Logger.Message,
metadata: @autoclosure () -> Logger.Metadata? = nil,
file: String = #file, function: String = #function, line: UInt = #line) {
self.log(level: level, message(), metadata: metadata(), source: nil, file: file, function: function, line: line)
}

/// Add, change, or remove a logging metadata item.
///
/// - note: Logging metadata behaves as a value that means a change to the logging metadata will only affect the
Expand Down Expand Up @@ -137,6 +160,25 @@ extension Logger {
self.log(level: .trace, message(), metadata: metadata(), source: source(), file: file, function: function, line: line)
}

/// If `.trace` is at least as severe as the `Logger`'s `logLevel`, it will be logged,
/// otherwise nothing will happen.
///
/// - parameters:
/// - message: The message to be logged. `message` can be used with any string interpolation literal.
/// - metadata: One-off metadata to attach to this log message
/// - file: The file this log message originates from (there's usually no need to pass it explicitly as it
/// defaults to `#file`).
/// - function: The function this log message originates from (there's usually no need to pass it explicitly as
/// it defaults to `#function`).
/// - line: The line this log message originates from (there's usually no need to pass it explicitly as it
/// defaults to `#line`).
@inlinable
public func trace(_ message: @autoclosure () -> Logger.Message,
metadata: @autoclosure () -> Logger.Metadata? = nil,
file: String = #file, function: String = #function, line: UInt = #line) {
self.trace(message(), metadata: metadata(), source: nil, file: file, line: line)
}

/// Log a message passing with the `Logger.Level.debug` log level.
///
/// If `.debug` is at least as severe as the `Logger`'s `logLevel`, it will be logged,
Expand All @@ -161,6 +203,27 @@ extension Logger {
self.log(level: .debug, message(), metadata: metadata(), source: source(), file: file, function: function, line: line)
}

/// Log a message passing with the `Logger.Level.debug` log level.
///
/// If `.debug` is at least as severe as the `Logger`'s `logLevel`, it will be logged,
/// otherwise nothing will happen.
///
/// - parameters:
/// - message: The message to be logged. `message` can be used with any string interpolation literal.
/// - metadata: One-off metadata to attach to this log message.
/// - file: The file this log message originates from (there's usually no need to pass it explicitly as it
/// defaults to `#file`).
/// - function: The function this log message originates from (there's usually no need to pass it explicitly as
/// it defaults to `#function`).
/// - line: The line this log message originates from (there's usually no need to pass it explicitly as it
/// defaults to `#line`).
@inlinable
public func debug(_ message: @autoclosure () -> Logger.Message,
metadata: @autoclosure () -> Logger.Metadata? = nil,
file: String = #file, function: String = #function, line: UInt = #line) {
self.debug(message(), metadata: metadata(), source: nil, file: file, function: function, line: line)
}

/// Log a message passing with the `Logger.Level.info` log level.
///
/// If `.info` is at least as severe as the `Logger`'s `logLevel`, it will be logged,
Expand All @@ -185,6 +248,27 @@ extension Logger {
self.log(level: .info, message(), metadata: metadata(), source: source(), file: file, function: function, line: line)
}

/// Log a message passing with the `Logger.Level.info` log level.
///
/// If `.info` is at least as severe as the `Logger`'s `logLevel`, it will be logged,
/// otherwise nothing will happen.
///
/// - parameters:
/// - message: The message to be logged. `message` can be used with any string interpolation literal.
/// - metadata: One-off metadata to attach to this log message.
/// - file: The file this log message originates from (there's usually no need to pass it explicitly as it
/// defaults to `#file`).
/// - function: The function this log message originates from (there's usually no need to pass it explicitly as
/// it defaults to `#function`).
/// - line: The line this log message originates from (there's usually no need to pass it explicitly as it
/// defaults to `#line`).
@inlinable
public func info(_ message: @autoclosure () -> Logger.Message,
metadata: @autoclosure () -> Logger.Metadata? = nil,
file: String = #file, function: String = #function, line: UInt = #line) {
self.info(message(), metadata: metadata(), source: nil, file: file, function: function, line: line)
}

/// Log a message passing with the `Logger.Level.notice` log level.
///
/// If `.notice` is at least as severe as the `Logger`'s `logLevel`, it will be logged,
Expand All @@ -209,6 +293,29 @@ extension Logger {
self.log(level: .notice, message(), metadata: metadata(), source: source(), file: file, function: function, line: line)
}

/// Log a message passing with the `Logger.Level.notice` log level.
///
/// If `.notice` is at least as severe as the `Logger`'s `logLevel`, it will be logged,
/// otherwise nothing will happen.
///
/// - parameters:
/// - message: The message to be logged. `message` can be used with any string interpolation literal.
/// - metadata: One-off metadata to attach to this log message.
/// - source: The source this log messages originates to. Currently, it defaults to the folder containing the
/// file that is emitting the log message, which usually is the module.
/// - file: The file this log message originates from (there's usually no need to pass it explicitly as it
/// defaults to `#file`).
/// - function: The function this log message originates from (there's usually no need to pass it explicitly as
/// it defaults to `#function`).
/// - line: The line this log message originates from (there's usually no need to pass it explicitly as it
/// defaults to `#line`).
@inlinable
public func notice(_ message: @autoclosure () -> Logger.Message,
metadata: @autoclosure () -> Logger.Metadata? = nil,
file: String = #file, function: String = #function, line: UInt = #line) {
self.notice(message(), metadata: metadata(), source: nil, file: file, function: function, line: line)
}

/// Log a message passing with the `Logger.Level.warning` log level.
///
/// If `.warning` is at least as severe as the `Logger`'s `logLevel`, it will be logged,
Expand All @@ -233,6 +340,27 @@ extension Logger {
self.log(level: .warning, message(), metadata: metadata(), source: source(), file: file, function: function, line: line)
}

/// Log a message passing with the `Logger.Level.warning` log level.
///
/// If `.warning` is at least as severe as the `Logger`'s `logLevel`, it will be logged,
/// otherwise nothing will happen.
///
/// - parameters:
/// - message: The message to be logged. `message` can be used with any string interpolation literal.
/// - metadata: One-off metadata to attach to this log message.
/// - file: The file this log message originates from (there's usually no need to pass it explicitly as it
/// defaults to `#file`).
/// - function: The function this log message originates from (there's usually no need to pass it explicitly as
/// it defaults to `#function`).
/// - line: The line this log message originates from (there's usually no need to pass it explicitly as it
/// defaults to `#line`).
@inlinable
public func warning(_ message: @autoclosure () -> Logger.Message,
metadata: @autoclosure () -> Logger.Metadata? = nil,
file: String = #file, function: String = #function, line: UInt = #line) {
self.warning(message(), metadata: metadata(), source: nil, file: file, function: function, line: line)
}

/// Log a message passing with the `Logger.Level.error` log level.
///
/// If `.error` is at least as severe as the `Logger`'s `logLevel`, it will be logged,
Expand All @@ -257,6 +385,27 @@ extension Logger {
self.log(level: .error, message(), metadata: metadata(), source: source(), file: file, function: function, line: line)
}

/// Log a message passing with the `Logger.Level.error` log level.
///
/// If `.error` is at least as severe as the `Logger`'s `logLevel`, it will be logged,
/// otherwise nothing will happen.
///
/// - parameters:
/// - message: The message to be logged. `message` can be used with any string interpolation literal.
/// - metadata: One-off metadata to attach to this log message.
/// - file: The file this log message originates from (there's usually no need to pass it explicitly as it
/// defaults to `#file`).
/// - function: The function this log message originates from (there's usually no need to pass it explicitly as
/// it defaults to `#function`).
/// - line: The line this log message originates from (there's usually no need to pass it explicitly as it
/// defaults to `#line`).
@inlinable
public func error(_ message: @autoclosure () -> Logger.Message,
metadata: @autoclosure () -> Logger.Metadata? = nil,
file: String = #file, function: String = #function, line: UInt = #line) {
self.error(message(), metadata: metadata(), source: nil, file: file, function: function, line: line)
}

/// Log a message passing with the `Logger.Level.critical` log level.
///
/// `.critical` messages will always be logged.
Expand All @@ -279,6 +428,28 @@ extension Logger {
file: String = #file, function: String = #function, line: UInt = #line) {
self.log(level: .critical, message(), metadata: metadata(), source: source(), file: file, function: function, line: line)
}

/// Log a message passing with the `Logger.Level.critical` log level.
///
/// `.critical` messages will always be logged.
///
/// - parameters:
/// - message: The message to be logged. `message` can be used with any string interpolation literal.
/// - metadata: One-off metadata to attach to this log message.
/// - source: The source this log messages originates to. Currently, it defaults to the folder containing the
/// file that is emitting the log message, which usually is the module.
/// - file: The file this log message originates from (there's usually no need to pass it explicitly as it
/// defaults to `#file`).
/// - function: The function this log message originates from (there's usually no need to pass it explicitly as
/// it defaults to `#function`).
/// - line: The line this log message originates from (there's usually no need to pass it explicitly as it
/// defaults to `#line`).
@inlinable
public func critical(_ message: @autoclosure () -> Logger.Message,
metadata: @autoclosure () -> Logger.Metadata? = nil,
file: String = #file, function: String = #function, line: UInt = #line) {
self.critical(message(), metadata: metadata(), source: nil, file: file, function: function, line: line)
}
}

/// The `LoggingSystem` is a global facility where the default logging backend implementation (`LogHandler`) can be
Expand Down
2 changes: 2 additions & 0 deletions Tests/LoggingTests/LoggingTest+XCTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ extension LoggingTest {
("testCustomFactory", testCustomFactory),
("testAllLogLevelsExceptCriticalCanBeBlocked", testAllLogLevelsExceptCriticalCanBeBlocked),
("testAllLogLevelsWork", testAllLogLevelsWork),
("testAllLogLevelByFunctionRefWithSource", testAllLogLevelByFunctionRefWithSource),
("testAllLogLevelByFunctionRefWithoutSource", testAllLogLevelByFunctionRefWithoutSource),
("testLogMessageWithStringInterpolation", testLogMessageWithStringInterpolation),
("testLoggingAString", testLoggingAString),
("testMultiplexerIsValue", testMultiplexerIsValue),
Expand Down
68 changes: 66 additions & 2 deletions Tests/LoggingTests/LoggingTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,70 @@ class LoggingTest: XCTestCase {
testLogging.history.assertExist(level: .critical, message: "yes: critical")
}

func testAllLogLevelByFunctionRefWithSource() {
let testLogging = TestLogging()
LoggingSystem.bootstrapInternal(testLogging.make)

var logger = Logger(label: "\(#function)")
logger.logLevel = .trace

let trace = logger.trace(_:metadata:source:file:function:line:)
let debug = logger.debug(_:metadata:source:file:function:line:)
let info = logger.info(_:metadata:source:file:function:line:)
let notice = logger.notice(_:metadata:source:file:function:line:)
let warning = logger.warning(_:metadata:source:file:function:line:)
let error = logger.error(_:metadata:source:file:function:line:)
let critical = logger.critical(_:metadata:source:file:function:line:)

trace("yes: trace", [:], "foo", #file, #function, #line)
debug("yes: debug", [:], "foo", #file, #function, #line)
info("yes: info", [:], "foo", #file, #function, #line)
notice("yes: notice", [:], "foo", #file, #function, #line)
warning("yes: warning", [:], "foo", #file, #function, #line)
error("yes: error", [:], "foo", #file, #function, #line)
critical("yes: critical", [:], "foo", #file, #function, #line)

testLogging.history.assertExist(level: .trace, message: "yes: trace", source: "foo")
testLogging.history.assertExist(level: .debug, message: "yes: debug", source: "foo")
testLogging.history.assertExist(level: .info, message: "yes: info", source: "foo")
testLogging.history.assertExist(level: .notice, message: "yes: notice", source: "foo")
testLogging.history.assertExist(level: .warning, message: "yes: warning", source: "foo")
testLogging.history.assertExist(level: .error, message: "yes: error", source: "foo")
testLogging.history.assertExist(level: .critical, message: "yes: critical", source: "foo")
}

func testAllLogLevelByFunctionRefWithoutSource() {
let testLogging = TestLogging()
LoggingSystem.bootstrapInternal(testLogging.make)

var logger = Logger(label: "\(#function)")
logger.logLevel = .trace

let trace = logger.trace(_:metadata:file:function:line:)
let debug = logger.debug(_:metadata:file:function:line:)
let info = logger.info(_:metadata:file:function:line:)
let notice = logger.notice(_:metadata:file:function:line:)
let warning = logger.warning(_:metadata:file:function:line:)
let error = logger.error(_:metadata:file:function:line:)
let critical = logger.critical(_:metadata:file:function:line:)

trace("yes: trace", [:], #file, #function, #line)
debug("yes: debug", [:], #file, #function, #line)
info("yes: info", [:], #file, #function, #line)
notice("yes: notice", [:], #file, #function, #line)
warning("yes: warning", [:], #file, #function, #line)
error("yes: error", [:], #file, #function, #line)
critical("yes: critical", [:], #file, #function, #line)

testLogging.history.assertExist(level: .trace, message: "yes: trace")
testLogging.history.assertExist(level: .debug, message: "yes: debug")
testLogging.history.assertExist(level: .info, message: "yes: info")
testLogging.history.assertExist(level: .notice, message: "yes: notice")
testLogging.history.assertExist(level: .warning, message: "yes: warning")
testLogging.history.assertExist(level: .error, message: "yes: error")
testLogging.history.assertExist(level: .critical, message: "yes: critical")
}

func testLogMessageWithStringInterpolation() {
let testLogging = TestLogging()
LoggingSystem.bootstrapInternal(testLogging.make)
Expand Down Expand Up @@ -733,14 +797,14 @@ class LoggingTest: XCTestCase {

var logger = Logger(label: "test")
logger.logLevel = .error
logger.error(Dummy())
logger.error(error: Dummy())

logging.history.assertExist(level: .error, message: "errorDescription")
}
}

extension Logger {
public func error(_ error: Error,
public func error(error: Error,
metadata: @autoclosure () -> Logger.Metadata? = nil,
file: String = #file, function: String = #function, line: UInt = #line) {
self.error("\(error.localizedDescription)", metadata: metadata(), file: file, function: function, line: line)
Expand Down

0 comments on commit 12d3a86

Please sign in to comment.