Skip to content

Commit

Permalink
#17: Rebasing: custom raw log location
Browse files Browse the repository at this point in the history
  • Loading branch information
KyNorthstar committed Jun 9, 2023
1 parent ea8289b commit 1823dd8
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 28 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ By default, severities are represented by emoji (like ℹ️ for `info` and 🆘

By default, this just logs to the same place as Swift's `print` statement. Because enterprise apps have different needs, it can also log to `stdout`, `stderr`, any `FileHandle`, or a custom function. Arbitrarily many of these can operate simultaneously. You can also specify this per-log-call or for all log calls.

**If none is specified, the default channel filter discards messages lower than `info` severity**, since that's the lowest built-in severity which users might care about if they're looking at the logs, but not debugging the code itself.
**If none is specified, the default channel filter discards messages lower than a severity which users might care about** if they're looking at the logs, but not debugging the code itself.

```swift
LogManager.defaultChannels += [
Expand Down
2 changes: 1 addition & 1 deletion Sources/SimpleLogging/LogChannel/LogChannel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public struct LogChannel<Location: UnreliableLogChannelLocation>: AnyLogChannel
/// - Parameters:
/// - name: The human-readable name of this channel
/// - location: The location to which this channel sends its log messages
/// - lowestAllowedSeverity: _optional_ - The lowest severity which will appear in this channel's logs. Defaults to `defaultFilter`, since that's the lowest built-in severity which users might care about if they're looking at logs, but not debugging the code itself.
/// - lowestAllowedSeverity: _optional_ - The lowest severity which will appear in this channel's logs. Defaults to `defaultFilter`
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`.
public init(
name: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@ public extension UnreliableLogChannelLocation where Self == CustomLogChannelLoca
public extension LogChannel where Location == CustomLogChannelLocation {

/// Log to a function, so you can implement some custom logging channel without defining a new `struct`.
///
///
/// The function is passed the fully-rendered log line, like
/// `"2020-11-20 05:26:49.178Z ⚠️ LogToFileTests.swift:144 testLogOnlyCriticalSeveritiesToFile() This message is a warning"`
///
///
/// - Parameters:
/// - logger: Passed the fully-rendered log line
/// - logger: Passed the fully-rendered log line
/// - name: The human-readable name of the channel
/// - severityFilter: _optional_ - The filter which decides which messages appear in this channel's logs. Defaults to allowing `info` and higher, since `info` is the lowest built-in severity which users might care about if they're looking at logs, but not debugging the code itself.
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.emoji`, so humans can more easily skim the log.
/// - lowestAllowedSeverity: _optional_ - The lowest severity level which is allowed in the log. Defaults to `.defaultFilter`
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`
static func custom(
name: String,
lowestAllowedSeverity: LogSeverity,
Expand All @@ -82,10 +82,10 @@ public extension LogChannel where Location == CustomLogChannelLocation {
/// `2020-11-20 05:26:49.178Z ⚠️ LogToFileTests.swift:144 testLogOnlyCriticalSeveritiesToFile() This message is a warning`
///
/// - Parameters:
/// - logger: Passed the fully-rendered log line
/// - logger: Passed the fully-rendered log line
/// - name: The human-readable name of the channel
/// - severityFilter: _optional_ - The filter which decides which messages appear in this channel's logs. Defaults to allowing `info` and higher, since `info` is the lowest built-in severity which users might care about if they're looking at logs, but not debugging the code itself.
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.emoji`, so humans can more easily skim the log.
/// - severityFilter: _optional_ - The filter which decides which messages appear in this channel's logs. Defaults to `.default`
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`
static func custom(
name: String,
severityFilter: LogSeverityFilter = .default,
Expand Down
134 changes: 134 additions & 0 deletions Sources/SimpleLogging/LogChannel/LogChannelLocation + customRaw.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
//
// LogChannelLocation + customRaw.swift
//
//
// Created by Ky Leggiero on 2023-06-08.
//

import Foundation
import FunctionTools



private let errorMessage_logNonRawMessageToRawLocation = "<<SimpleLogging: Attempted to log non-raw message to raw location>>"



/// Log to a function, so you can implement some custom logging location where you assemble it yourself.
///
/// The function is passed completely unrendered log message components. See the documentation for `RawLogMessage` for more info.
///
/// Log channels may choose to pre-filter messages before that function is called.
public struct CustomRawLogChannelLocation: LogChannelLocation {

/// API users give us this to tell us where/how to log messages
private let logger: Callback<RawLogMessage>


/// Create a new custom log channel location
///
/// The function is passed the raw data about what to log.
/// Log channels may choose to pre-filter messages before that function is called.
///
/// - Parameter logger: Passed the raw, unrendered log message & metadata
init(loggingTo logger: @escaping Callback<RawLogMessage>) {
self.logger = logger
}


public func append(_ message: LogMessageProtocol, options: LoggingOptions) {
if let message = message as? RawLogMessage {
logger(message)
}
else {
assertionFailure(
"""
When logging to a raw location, `message` must be a `RawLogMessage`.
Instead, this was received: \(type(of: message))
In prodiction, this will be logged as a rendered log line, along with info about this failure, with `error` severity to Swift's `print` destination.
Production lines will have the following text inside them:
\(errorMessage_logNonRawMessageToRawLocation)
The entire rendered log line (including this error and the original severity) will be placed in the message location of the log line.
Because `RawLogMessage` is the only built-in message which knows its code location, a dummy code location will be used instead, with a file path of `"error"`, a function name of `"error"`, and a line number of `0xbad_c0de` (`195936478`).
"""
)

print(
RawLogMessage(
dateLogged: message.dateLogged,
severity: .error,
codeLocation: CodeLocation(fullFilePath: "error", functionIdentifier: "error", lineNumber: 0xbad_c0de),
message: "\t \(errorMessage_logNonRawMessageToRawLocation)\t \(message.entireRenderedLogLine(options: options))"
)
.entireRenderedLogLine(options: options))
}
}
}



public extension UnreliableLogChannelLocation where Self == CustomRawLogChannelLocation {

/// Log to a function, so you can implement some custom logging location where you assemble it yourself.
///
/// The function is passed completely unrendered log message components. See the documentation for `RawLogMessage` for more info.
///
/// Log channels may choose to pre-filter messages before that function is called.
///
/// - Parameter logger: Passed the raw, unrendered log message & metadata
static func customRaw(loggingTo logger: @escaping Callback<RawLogMessage>) -> Self {
.init(loggingTo: logger)
}
}



public extension LogChannel where Location == CustomRawLogChannelLocation {
/// Log to a function, so you can implement some custom logging location where you assemble it yourself.
///
/// The function is passed completely unrendered log message components. See the documentation for `RawLogMessage` for more info.
///
/// Log channels may choose to pre-filter messages before that function is called.
///
/// - Parameters:
/// - name: The human-readable name of the channel
/// - lowestAllowedSeverity: _optional_ - The lowest severity which will appear in this channel's logs. Defaults to `.defaultFilter`
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`
/// - logger: Passed the raw, unrendered log message & metadata
func customRaw(
name: String,
lowestAllowedSeverity: LogSeverity,
logSeverityNameStyle: SeverityNameStyle = .default,
logger: @escaping Callback<RawLogMessage>)
-> Self {
.init(name: name,
location: Location(loggingTo: logger),
lowestAllowedSeverity: lowestAllowedSeverity,
logSeverityNameStyle: logSeverityNameStyle)
}


/// Log to a function, so you can implement some custom logging channel without defining a new `struct`.
///
/// The function is passed the fully-rendered log line, like
/// `2020-11-20 05:26:49.178Z ⚠️ LogToFileTests.swift:144 testLogOnlyCriticalSeveritiesToFile() This message is a warning`
///
/// - Parameters:
/// - name: The human-readable name of the channel
/// - severityFilter: _optional_ - The filter which decides which messages appear in this channel's logs. Defaults to `.default`
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`
/// - logger: Passed the raw, unrendered log message & metadata
static func custom(
name: String,
severityFilter: LogSeverityFilter = .default,
logSeverityNameStyle: SeverityNameStyle = .default,
logger: @escaping Callback<RawLogMessage>)
-> Self {
.init(name: name,
location: Location(loggingTo: logger),
severityFilter: severityFilter,
logSeverityNameStyle: logSeverityNameStyle)
}
}
12 changes: 6 additions & 6 deletions Sources/SimpleLogging/LogChannel/LogChannelLocation + file.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public extension LogChannel where Location == FileLogChannelLocation {
/// - fileManager: _optional_ - The file manager to use when performing file system operations. Defaults to `.default`.
/// - name: _optional_ - The human-readable name of the channel. Pass `nil` to generate one based on the path. Defaults to `nil`.
/// - severityFilter: _optional_ - The filter which decides which messages appear in this channel's logs. Defaults to allowing `info` and higher, since `info` is the lowest built-in severity which users might care about if they're looking at logs, but not debugging the code itself.
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.emoji`, so humans can more easily skim the log.
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`
///
/// - Throws: If the parent directory cannot be created, or if you specified that it shouldn't be but it doesn't exist, or if the log file cannot ce created, or if the file couldn't be opened for writing
static func file(
Expand Down Expand Up @@ -161,8 +161,8 @@ public extension LogChannel where Location == FileLogChannelLocation {
/// - createIntermediatesIfNecessary: _optional_ - If the parent directory, or any of its ancestor directories, doesn't exist, then passing `true` will cause this to attempt to create it, whereas if you pass `false`, then this will throw an error if they don't exist. Defaults to `true`.
/// - fileManager: _optional_ - The file manager to use when performing file system operations. Defaults to `.default`.
/// - name: _optional_ - The human-readable name of the channel. Pass `nil` to generate one based on the path. Defaults to `nil`.
/// - lowestAllowedSeverity: _optional_ - The lowest severity which will appear in this channel's logs. Defaults to `info`, since that's the lowest built-in severity which users might care about if they're looking at logs, but not debugging the code itself.
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.emoji`, so humans can more easily skim the log.
/// - lowestAllowedSeverity: _optional_ - The lowest severity which will appear in this channel's logs. Defaults to `defaultFilter`
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`
///
/// - Throws: If the parent directory cannot be created, or if you specified that it shouldn't be but it doesn't exist, or if the log file cannot ce created, or if the file couldn't be opened for writing
static func file(
Expand Down Expand Up @@ -195,7 +195,7 @@ public extension LogChannel where Location == FileLogChannelLocation {
/// - fileManager: _optional_ - The file manager to use when performing file system operations. Defaults to `.default`.
/// - name: _optional_ - The human-readable name of the channel. Pass `nil` to generate one based on the path. Defaults to `nil`.
/// - severityFilter: _optional_ - The filter which decides which messages appear in this channel's logs. Defaults to allowing `info` and higher, since `info` is the lowest built-in severity which users might care about if they're looking at logs, but not debugging the code itself.
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.emoji`, so humans can more easily skim the log.
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`
///
/// - Throws: If the parent directory cannot be created, or if you specified that it shouldn't be but it doesn't exist, or if the log file cannot ce created, or if the file couldn't be opened for writing
static func file(
Expand Down Expand Up @@ -227,8 +227,8 @@ public extension LogChannel where Location == FileLogChannelLocation {
/// - createIntermediatesIfNecessary: _optional_ - If the parent directory, or any of its ancestor directories, doesn't exist, then passing `true` will cause this to attempt to create it, whereas if you pass `false`, then this will throw an error if they don't exist. Defaults to `true`.
/// - fileManager: _optional_ - The file manager to use when performing file system operations. Defaults to `.default`.
/// - name: _optional_ - The human-readable name of the channel. Pass `nil` to generate one based on the path. Defaults to `nil`.
/// - lowestAllowedSeverity: _optional_ - The lowest severity which will appear in this channel's logs. Defaults to `info`, since that's the lowest built-in severity which users might care about if they're looking at logs, but not debugging the code itself.
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.emoji`, so humans can more easily skim the log.
/// - lowestAllowedSeverity: _optional_ - The lowest severity which will appear in this channel's logs. Defaults to `defaultFilter`
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`
///
/// - Throws: If the parent directory cannot be created, or if you specified that it shouldn't be but it doesn't exist, or if the log file cannot ce created, or if the file couldn't be opened for writing
static func file(
Expand Down
Loading

0 comments on commit 1823dd8

Please sign in to comment.