Skip to content

Commit

Permalink
docs: add structured logging docs in code formatting rules doc
Browse files Browse the repository at this point in the history
  • Loading branch information
ellemouton committed Dec 2, 2024
1 parent a04f8df commit efe08b8
Showing 1 changed file with 89 additions and 0 deletions.
89 changes: 89 additions & 0 deletions docs/code_formatting_rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,95 @@ be used for calls to formatting functions like `fmt.Errorf`,
But not for statements that are important for the flow or logic of the code,
like `require.NoErrorf()`.

#### Exceptions and additional styling for structured logging

When making use of structured logging calls (there are any `btclog.Logger`
methods ending in `S`), a few different rules and exceptions apply.

1) **Static messages:** Structured log calls take a `context.Context` as a first
parameter and a _static_ string as the second parameter (the `msg` parameter).
Formatted strings should ideally not be used for the construction of the `msg`
parameter. Instead, key-value pairs (or `slog` attributes) should be used to
provide additional variables to the log line.

**WRONG**
```go
log.DebugS(ctx, fmt.Sprintf("User %d just spent %.8f to open a channel", userID, 0.0154))
```

**RIGHT**
```go
log.InfoS(ctx, "Channel open performed",
slog.Int("user_id", userID),
btclog.Fmt("amount", "%.8f", 0.00154))
```

2) **Key-value attributes**: The third parameter in any structured log method is
a variadic list of the `any` type but it is required that these are provided in
key-value pairs such that an associated `slog.Attr` variable can be created for
each key-value pair. The simplest way to specify this is to directly pass in the
key-value pairs as raw literals as follows:

```go
log.InfoS(ctx, "Channel open performed", "user_id", userID, "amount", 0.00154)
```
This does work, but it becomes easy to make a mistake and accidentally leave out
a value for each key provided leading to a nonsensical log line. To avoid this,
it is suggested to make use of the various `slog.Attr` helper functions as
follows:

```go
log.InfoS(ctx, "Channel open performed",
slog.Int("user_id", userID),
btclog.Fmt("amount", "%.8f", 0.00154))
```

3) **Line wrapping**: Structured log lines are an exception to the 80-character
line wrapping rule. This is so that the key-value pairs can be easily read and
reasoned about. If it is the case that there is only a single key-value pair
and the entire log line is still less than 80 characters, it is acceptable to
have the key-value pair on the same line as the log message. However, if there
are multiple key-value pairs, it is suggested to use the one line per key-value
pair format. Due to this suggestion, it is acceptable for any single key-value
pair line to exceed 80 characters for the sake of readability.

**WRONG**
```go
// Example 1.
log.InfoS(ctx, "User connected",
"user_id", userID)

// Example 2.
log.InfoS(ctx, "Channel open performed", "user_id", userID,
btclog.Fmt("amount", "%.8f", 0.00154), "channel_id", channelID)

// Example 3.
log.InfoS(ctx, "Bytes received",
"user_id", userID,
btclog.Hex("peer_id", peerID.SerializeCompressed()),
btclog.Hex("message", []bytes{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
})))
```

**RIGHT**
```go
// Example 1.
log.InfoS(ctx, "User connected", "user_id", userID)

// Example 2.
log.InfoS(ctx, "Channel open performed",
slog.Int("user_id", userID),
btclog.Fmt("amount", "%.8f", 0.00154),
slog.String("channel_id", channelID))

// Example 3.
log.InfoS(ctx, "Bytes received",
"user_id", userID,
btclog.Hex("peer_id", peerID.SerializeCompressed()),
btclog.Hex("message", []bytes{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08})))
```

### Wrapping long function definitions

If one is forced to wrap lines of function arguments that exceed the
Expand Down

0 comments on commit efe08b8

Please sign in to comment.