Skip to content

Commit 1823dd8

Browse files
committed
#17: Rebasing: custom raw log location
1 parent ea8289b commit 1823dd8

8 files changed

Lines changed: 164 additions & 28 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ By default, severities are represented by emoji (like ℹ️ for `info` and 🆘
7272

7373
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.
7474

75-
**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.
75+
**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.
7676

7777
```swift
7878
LogManager.defaultChannels += [

Sources/SimpleLogging/LogChannel/LogChannel.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public struct LogChannel<Location: UnreliableLogChannelLocation>: AnyLogChannel
8282
/// - Parameters:
8383
/// - name: The human-readable name of this channel
8484
/// - location: The location to which this channel sends its log messages
85-
/// - 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.
85+
/// - lowestAllowedSeverity: _optional_ - The lowest severity which will appear in this channel's logs. Defaults to `defaultFilter`
8686
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`.
8787
public init(
8888
name: String,

Sources/SimpleLogging/LogChannel/LogChannelLocation + custom.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,15 @@ public extension UnreliableLogChannelLocation where Self == CustomLogChannelLoca
5454
public extension LogChannel where Location == CustomLogChannelLocation {
5555

5656
/// Log to a function, so you can implement some custom logging channel without defining a new `struct`.
57-
///
57+
///
5858
/// The function is passed the fully-rendered log line, like
5959
/// `"2020-11-20 05:26:49.178Z ⚠️ LogToFileTests.swift:144 testLogOnlyCriticalSeveritiesToFile() This message is a warning"`
60-
///
60+
///
6161
/// - Parameters:
62-
/// - logger: Passed the fully-rendered log line
62+
/// - logger: Passed the fully-rendered log line
6363
/// - name: The human-readable name of the channel
64-
/// - 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.
65-
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.emoji`, so humans can more easily skim the log.
64+
/// - lowestAllowedSeverity: _optional_ - The lowest severity level which is allowed in the log. Defaults to `.defaultFilter`
65+
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`
6666
static func custom(
6767
name: String,
6868
lowestAllowedSeverity: LogSeverity,
@@ -82,10 +82,10 @@ public extension LogChannel where Location == CustomLogChannelLocation {
8282
/// `2020-11-20 05:26:49.178Z ⚠️ LogToFileTests.swift:144 testLogOnlyCriticalSeveritiesToFile() This message is a warning`
8383
///
8484
/// - Parameters:
85-
/// - logger: Passed the fully-rendered log line
85+
/// - logger: Passed the fully-rendered log line
8686
/// - name: The human-readable name of the channel
87-
/// - 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.
88-
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.emoji`, so humans can more easily skim the log.
87+
/// - severityFilter: _optional_ - The filter which decides which messages appear in this channel's logs. Defaults to `.default`
88+
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`
8989
static func custom(
9090
name: String,
9191
severityFilter: LogSeverityFilter = .default,
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
//
2+
// LogChannelLocation + customRaw.swift
3+
//
4+
//
5+
// Created by Ky Leggiero on 2023-06-08.
6+
//
7+
8+
import Foundation
9+
import FunctionTools
10+
11+
12+
13+
private let errorMessage_logNonRawMessageToRawLocation = "<<SimpleLogging: Attempted to log non-raw message to raw location>>"
14+
15+
16+
17+
/// Log to a function, so you can implement some custom logging location where you assemble it yourself.
18+
///
19+
/// The function is passed completely unrendered log message components. See the documentation for `RawLogMessage` for more info.
20+
///
21+
/// Log channels may choose to pre-filter messages before that function is called.
22+
public struct CustomRawLogChannelLocation: LogChannelLocation {
23+
24+
/// API users give us this to tell us where/how to log messages
25+
private let logger: Callback<RawLogMessage>
26+
27+
28+
/// Create a new custom log channel location
29+
///
30+
/// The function is passed the raw data about what to log.
31+
/// Log channels may choose to pre-filter messages before that function is called.
32+
///
33+
/// - Parameter logger: Passed the raw, unrendered log message & metadata
34+
init(loggingTo logger: @escaping Callback<RawLogMessage>) {
35+
self.logger = logger
36+
}
37+
38+
39+
public func append(_ message: LogMessageProtocol, options: LoggingOptions) {
40+
if let message = message as? RawLogMessage {
41+
logger(message)
42+
}
43+
else {
44+
assertionFailure(
45+
"""
46+
When logging to a raw location, `message` must be a `RawLogMessage`.
47+
Instead, this was received: \(type(of: message))
48+
49+
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.
50+
Production lines will have the following text inside them:
51+
\(errorMessage_logNonRawMessageToRawLocation)
52+
53+
The entire rendered log line (including this error and the original severity) will be placed in the message location of the log line.
54+
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`).
55+
"""
56+
)
57+
58+
print(
59+
RawLogMessage(
60+
dateLogged: message.dateLogged,
61+
severity: .error,
62+
codeLocation: CodeLocation(fullFilePath: "error", functionIdentifier: "error", lineNumber: 0xbad_c0de),
63+
message: "\t \(errorMessage_logNonRawMessageToRawLocation)\t \(message.entireRenderedLogLine(options: options))"
64+
)
65+
.entireRenderedLogLine(options: options))
66+
}
67+
}
68+
}
69+
70+
71+
72+
public extension UnreliableLogChannelLocation where Self == CustomRawLogChannelLocation {
73+
74+
/// Log to a function, so you can implement some custom logging location where you assemble it yourself.
75+
///
76+
/// The function is passed completely unrendered log message components. See the documentation for `RawLogMessage` for more info.
77+
///
78+
/// Log channels may choose to pre-filter messages before that function is called.
79+
///
80+
/// - Parameter logger: Passed the raw, unrendered log message & metadata
81+
static func customRaw(loggingTo logger: @escaping Callback<RawLogMessage>) -> Self {
82+
.init(loggingTo: logger)
83+
}
84+
}
85+
86+
87+
88+
public extension LogChannel where Location == CustomRawLogChannelLocation {
89+
/// Log to a function, so you can implement some custom logging location where you assemble it yourself.
90+
///
91+
/// The function is passed completely unrendered log message components. See the documentation for `RawLogMessage` for more info.
92+
///
93+
/// Log channels may choose to pre-filter messages before that function is called.
94+
///
95+
/// - Parameters:
96+
/// - name: The human-readable name of the channel
97+
/// - lowestAllowedSeverity: _optional_ - The lowest severity which will appear in this channel's logs. Defaults to `.defaultFilter`
98+
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`
99+
/// - logger: Passed the raw, unrendered log message & metadata
100+
func customRaw(
101+
name: String,
102+
lowestAllowedSeverity: LogSeverity,
103+
logSeverityNameStyle: SeverityNameStyle = .default,
104+
logger: @escaping Callback<RawLogMessage>)
105+
-> Self {
106+
.init(name: name,
107+
location: Location(loggingTo: logger),
108+
lowestAllowedSeverity: lowestAllowedSeverity,
109+
logSeverityNameStyle: logSeverityNameStyle)
110+
}
111+
112+
113+
/// Log to a function, so you can implement some custom logging channel without defining a new `struct`.
114+
///
115+
/// The function is passed the fully-rendered log line, like
116+
/// `2020-11-20 05:26:49.178Z ⚠️ LogToFileTests.swift:144 testLogOnlyCriticalSeveritiesToFile() This message is a warning`
117+
///
118+
/// - Parameters:
119+
/// - name: The human-readable name of the channel
120+
/// - severityFilter: _optional_ - The filter which decides which messages appear in this channel's logs. Defaults to `.default`
121+
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`
122+
/// - logger: Passed the raw, unrendered log message & metadata
123+
static func custom(
124+
name: String,
125+
severityFilter: LogSeverityFilter = .default,
126+
logSeverityNameStyle: SeverityNameStyle = .default,
127+
logger: @escaping Callback<RawLogMessage>)
128+
-> Self {
129+
.init(name: name,
130+
location: Location(loggingTo: logger),
131+
severityFilter: severityFilter,
132+
logSeverityNameStyle: logSeverityNameStyle)
133+
}
134+
}

Sources/SimpleLogging/LogChannel/LogChannelLocation + file.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public extension LogChannel where Location == FileLogChannelLocation {
131131
/// - fileManager: _optional_ - The file manager to use when performing file system operations. Defaults to `.default`.
132132
/// - name: _optional_ - The human-readable name of the channel. Pass `nil` to generate one based on the path. Defaults to `nil`.
133133
/// - 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.
134-
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.emoji`, so humans can more easily skim the log.
134+
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`
135135
///
136136
/// - 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
137137
static func file(
@@ -161,8 +161,8 @@ public extension LogChannel where Location == FileLogChannelLocation {
161161
/// - 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`.
162162
/// - fileManager: _optional_ - The file manager to use when performing file system operations. Defaults to `.default`.
163163
/// - name: _optional_ - The human-readable name of the channel. Pass `nil` to generate one based on the path. Defaults to `nil`.
164-
/// - 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.
165-
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.emoji`, so humans can more easily skim the log.
164+
/// - lowestAllowedSeverity: _optional_ - The lowest severity which will appear in this channel's logs. Defaults to `defaultFilter`
165+
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`
166166
///
167167
/// - 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
168168
static func file(
@@ -195,7 +195,7 @@ public extension LogChannel where Location == FileLogChannelLocation {
195195
/// - fileManager: _optional_ - The file manager to use when performing file system operations. Defaults to `.default`.
196196
/// - name: _optional_ - The human-readable name of the channel. Pass `nil` to generate one based on the path. Defaults to `nil`.
197197
/// - 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.
198-
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.emoji`, so humans can more easily skim the log.
198+
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`
199199
///
200200
/// - 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
201201
static func file(
@@ -227,8 +227,8 @@ public extension LogChannel where Location == FileLogChannelLocation {
227227
/// - 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`.
228228
/// - fileManager: _optional_ - The file manager to use when performing file system operations. Defaults to `.default`.
229229
/// - name: _optional_ - The human-readable name of the channel. Pass `nil` to generate one based on the path. Defaults to `nil`.
230-
/// - 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.
231-
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.emoji`, so humans can more easily skim the log.
230+
/// - lowestAllowedSeverity: _optional_ - The lowest severity which will appear in this channel's logs. Defaults to `defaultFilter`
231+
/// - logSeverityNameStyle: _optional_ - The style of the severity names that appear in the log. Defaults to `.default`
232232
///
233233
/// - 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
234234
static func file(

0 commit comments

Comments
 (0)