123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- package log
- import (
- "bytes"
- "context"
- "encoding/json"
- "fmt"
- "net"
- "reflect"
- "time"
- )
- // TimeFormat is [time.RFC3339Nano] with nanoseconds padded using
- // zeros to ensure the formatted time is always the same number of
- // characters.
- // Based on RFC3339NanoFixed from github.com/containerd/log
- const TimeFormat = "2006-01-02T15:04:05.000000000Z07:00"
- func FormatTime(t time.Time) string {
- return t.Format(TimeFormat)
- }
- // DurationFormat formats a [time.Duration] log entry.
- //
- // A nil value signals an error with the formatting.
- type DurationFormat func(time.Duration) interface{}
- func DurationFormatString(d time.Duration) interface{} { return d.String() }
- func DurationFormatSeconds(d time.Duration) interface{} { return d.Seconds() }
- func DurationFormatMilliseconds(d time.Duration) interface{} { return d.Milliseconds() }
- // FormatIO formats net.Conn and other types that have an `Addr()` or `Name()`.
- //
- // See FormatEnabled for more information.
- func FormatIO(ctx context.Context, v interface{}) string {
- m := make(map[string]string)
- m["type"] = reflect.TypeOf(v).String()
- switch t := v.(type) {
- case net.Conn:
- m["localAddress"] = formatAddr(t.LocalAddr())
- m["remoteAddress"] = formatAddr(t.RemoteAddr())
- case interface{ Addr() net.Addr }:
- m["address"] = formatAddr(t.Addr())
- default:
- return Format(ctx, t)
- }
- return Format(ctx, m)
- }
- func formatAddr(a net.Addr) string {
- return a.Network() + "://" + a.String()
- }
- // Format formats an object into a JSON string, without any indendtation or
- // HTML escapes.
- // Context is used to output a log waring if the conversion fails.
- //
- // This is intended primarily for `trace.StringAttribute()`
- func Format(ctx context.Context, v interface{}) string {
- b, err := encode(v)
- if err != nil {
- G(ctx).WithError(err).Warning("could not format value")
- return ""
- }
- return string(b)
- }
- func encode(v interface{}) ([]byte, error) {
- return encodeBuffer(&bytes.Buffer{}, v)
- }
- func encodeBuffer(buf *bytes.Buffer, v interface{}) ([]byte, error) {
- enc := json.NewEncoder(buf)
- enc.SetEscapeHTML(false)
- enc.SetIndent("", "")
- if err := enc.Encode(v); err != nil {
- err = fmt.Errorf("could not marshall %T to JSON for logging: %w", v, err)
- return nil, err
- }
- // encoder.Encode appends a newline to the end
- return bytes.TrimSpace(buf.Bytes()), nil
- }
|