Skip to content
This repository was archived by the owner on Aug 5, 2022. It is now read-only.

Commit af6db0b

Browse files
authored
Merge pull request #34 from wsargent/patch-2
High level feedback of log-levels.md
2 parents 9516314 + 1f75efa commit af6db0b

File tree

1 file changed

+16
-15
lines changed

1 file changed

+16
-15
lines changed

docs/log-levels.md

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Log Levels
22

3-
This guide serves as guidelines for library authors with regards to what [SwiftLog](https://github.com/apple/swift-log) log levels are appropriate for use in libraries, and in what situations to use what level.
3+
This guide serves as guidelines for library authors with regards to what [SwiftLog](https://github.com/apple/swift-log) log levels are appropriate for use in libraries, and in which situations to use which level.
44

55
## Guidelines for Libraries
66

@@ -14,28 +14,29 @@ SwiftLog defines the following 7 log levels via the [`Logger.Level` enum](https:
1414
* `error`
1515
* `critical`
1616

17-
Out of those, only levels _less severe than_ info (exclusive) are generally okay to be used by libraries.
17+
Out of those, only levels _less severe than_ info (exclusively) are generally okay to be used by libraries.
18+
1819
In the following section we'll explore how to use them in practice.
1920

2021
### Recommended log levels
2122

2223
It is always fine for a library to log at `trace` and `debug` levels, and these two should be the primary levels any library is logging at.
2324

24-
`trace` is the finest log level, and end-users of a library will not usually use it unless debugging very specific issues. You should consider it as a way for library developers to "log everything we could possibly need to diagnose a hard to reproduce bug." It is expected to take a toll on the performance of a system, and developers can assume trace level logging will not be used in production deployments, unless enabled specifically to locate some specific issue.
25+
`trace` is the finest log level, and end-users of a library will not usually use it unless debugging very specific issues. You should consider it as a way for library developers to "log everything we could possibly need to diagnose a hard to reproduce bug." Unrestricted logging at `trace` level may take a toll on the performance of a system, and developers can assume trace level logging will not be used in production deployments, unless enabled specifically to locate some specific issue.
2526

2627
This is in contrast with `debug` which some users _may_ choose to run enabled on their production systems.
2728

2829
> Debug level logging should be not "too" noisy. Developers should assume some production deployments may need to (or want to) run with debug level logging enabled.
2930
>
3031
> Debug level logging should not completely undermine the performance of a production system.
3132
32-
As such, `debug` logging should not be overly noisy. It should provide a high value understanding of what is going on in the library for end users without diving deep into its internals. This is what `trace` is intended for.
33+
As such, `debug` logging should provide a high value understanding of what is going on in the library for end users, using domain relevant language. Logging at `debug` level should not be overly noisy or dive deep into internals; this is what `trace` is intended for.
3334

34-
Use `warning` level sparingly. Whenever possible, try to rather return or throw `Error` to end users that are descriptive enough so they can inspect, log them and figure out the issue. Potentially they may then enable debug logging to find out more about the issue.
35+
Use `warning` level sparingly. Whenever possible, try to rather return or throw `Error` to end users that are descriptive enough so they can inspect, log them and figure out the issue. Potentially, they may then enable debug logging to find out more about the issue.
3536

3637
It is okay to log a `warning` "once", for example on system startup. This may include some one off "more secure configuration is available, try upgrading to it!" log statement upon a server's startup. You may also log warnings from background processes, which otherwise have no other means of informing the end user about some issue.
3738

38-
Logging on `error` level is similar to warnings: prefer to avoid doing so whenever possible. Instead, report errors via your library's API. For example, it is _not_ a good idea to log "connection failed" from an HTTP client. Perhaps the end-user intended to make this request to a known offline server to _confirm_ it is offline? From their perspective this connection error is not a "real" error, it is just what they expected -- as such the HTTP client should return or throw such an error, but _not_ log it.
39+
Logging on `error` level is similar to warnings: prefer to avoid doing so whenever possible. Instead, report errors via your library's API. For example, it is _not_ a good idea to log "connection failed" from an HTTP client. Perhaps the end-user intended to make this request to a known offline server to _confirm_ it is offline? From their perspective, this connection error is not a "real" error, it is just what they expected -- as such the HTTP client should return or throw such an error, but _not_ log it.
3940

4041
Do also note that in situations when you decide to log an error, be mindful of error rates. Will this error potentially be logged for every single operation while some network failure is happening? Some teams and companies have alerting systems set up based on the rate of errors logged in a system, and if it exceeds some threshold it may start calling and paging people in the middle of the night. When logging at error level, consider if the issue indeed is something that should be waking up people at night. You may also want to consider offering configuration in your library: "at what log level should this issue be reported?" This can come in handy in clustered systems which may log network failures themselves, or depend on external systems detecting and reporting this.
4142

@@ -48,13 +49,13 @@ Some libraries and situations may not be entirely clear with regards to what log
4849
`trace` level logging:
4950

5051
- Could include various additional information about a request, such as various diagnostics about created data structures, the state of caches or similar, which are created in order to serve a request.
51-
- Could include "begin operation" and "end operation" logs.
52-
- However, please consider using [swift-distributed-tracing](https://github.com/apple/swift-distributed-tracing) to instrument "begin" and "end" events, as tracing can be more efficient than logging. Logging may need to create string representations of the durations, log levels, and other fields.
52+
- Could include "begin operation" and "end operation" logging statements.
53+
- However, please consider using [swift-distributed-tracing](https://github.com/apple/swift-distributed-tracing) to instrument "begin" and "end" events, as tracing can be more efficient than logging. Logging may need to create string representations of the durations, log levels, and other fields.
5354

5455
`debug` level logging:
5556

5657
- May include a single log statement for opening a connection, accepting a request, and so on.
57-
- It can include a _high level_ overview of what is going on in the library. For example: "started work, processing step X, finished work X, result code 200".
58+
- It can include a _high level_ overview of control flow in an operation. For example: "started work, processing step X, made X decision, finished work X, result code 200". This overview may consist of high cardinality structured data.
5859

5960
### Log levels to avoid
6061

@@ -104,11 +105,11 @@ And a minor yet important hint: avoid inserting newlines and other control chara
104105

105106
#### Structured Logging (Semantic Logging)
106107

107-
Libraries may want to embrace the structured logging style.
108+
Libraries may want to embrace the structured logging style, which renders logs in a [semi-structured data format](https://en.wikipedia.org/wiki/Semi-structured_data).
108109

109-
It is a fantastic pattern which makes consuming logs in automated systems, and through grepping and other means much easier and future proof.
110+
It is a fantastic pattern which makes it easier and more reliable for automated code to process logged information.
110111

111-
Consider the following not structured log statement:
112+
Consider the following "not structured" log statement:
112113

113114
```swift
114115
// NOT structured logging style
@@ -137,7 +138,7 @@ log.info("Accepted connection", metadata: [
137138
// <date> info [connection.id:?,connection.peer:?, connections.total:?] Accepted connection
138139
```
139140

140-
This structured log can be formatted, depending on the logging backend, slightly differently on various systems. Even in the simple string representation of such log, we'd be able to grep for `connections.total: 100` rather than having to guess the correct string.
141+
This structured log can be formatted, depending on the logging backend, slightly differently on various systems. Even in the simple string representation of such a log, we'd be able to grep for `connections.total: 100` rather than having to guess the correct string.
141142

142143
Also, since the message now does not contain all that much "human readable wording", it is less prone to randomly change from "Accepted" to "We have accepted" or vice versa. This kind of change could break alerting systems which are set up to parse and alert on specific log messages.
143144

@@ -202,8 +203,8 @@ These are only general guidelines, and there always will be exceptions to these
202203

203204
Here are a few examples of situations when logging a message on a relatively high level might still be tolerable for a library.
204205

205-
It's permissible for a library to log at `critical` level right before a _hard crash_, as a last resort of informing the log collection systems or end-user about additional information detailing the reason for the crash. This should be _in addition to_ the message from a `fatalError` and can lead to an improved diagnosis/debugging experience for end users.
206+
It's permissible for a library to log at `critical` level right before a _hard_ crash of the process, as a last resort of informing the log collection systems or end-user about additional information detailing the reason for the crash. This should be _in addition to_ the message from a `fatalError` and can lead to an improved diagnosis/debugging experience for end users.
206207

207-
Sometimes libraries may be able to detect a harmful misconfiguration of the library. For example, selecting deprecated protocol versions. In such situations it may be useful to inform users in production by issuing a `warning`. However you should ensure that the warning is not logged repeatedly! For example, it is not acceptable for an HTTP client to log a warning on every single http request using some misconfiguration of the client. It _may_ be acceptable however for the client to log such warning, for example, _once_ at configuration time, if the library has a good way to do this.
208+
Sometimes libraries may be able to detect a harmful misconfiguration of the library. For example, selecting deprecated protocol versions. In such situations it may be useful to inform users in production by issuing a `warning`. However you should ensure that the warning is not logged repeatedly! For example, it is not acceptable for an HTTP client to log a warning on every single http request using some misconfiguration of the client. It _may_ be acceptable however for the client to log such a warning, for example, _once_ at configuration time, if the library has a good way to do this.
208209

209210
Some libraries may implement a "log this warning only once", "log this warning only at startup", "log this error only once an hour", or similar tricks to keep the noise level low but still informative enough to not be missed. This is, however, usually a pattern reserved for stateful long running libraries, rather than clients of databases and related persistent stores.

0 commit comments

Comments
 (0)