(ctx context.Context, ent slog.SinkEntry)
| 50 | } |
| 51 | |
| 52 | func (s stackdriverSink) LogEntry(ctx context.Context, ent slog.SinkEntry) { |
| 53 | // Note that these documents are inconsistent, so we only use the special |
| 54 | // keys described by both. |
| 55 | // https://cloud.google.com/logging/docs/agent/configuration#special-fields |
| 56 | // https://cloud.google.com/stackdriver/docs/solutions/agents/ops-agent/configuration#special-fields |
| 57 | e := slog.M( |
| 58 | slog.F("logging.googleapis.com/severity", sev(ent.Level)), |
| 59 | slog.F("severity", sev(ent.Level)), |
| 60 | slog.F("message", ent.Message), |
| 61 | // Unfortunately, both of these fields are required. |
| 62 | slog.F("timestampSeconds", ent.Time.Unix()), |
| 63 | slog.F("timestampNanos", ent.Time.UnixNano()%1e9), |
| 64 | slog.F("logging.googleapis.com/sourceLocation", &loggingpb.LogEntrySourceLocation{ |
| 65 | File: ent.File, |
| 66 | Line: int64(ent.Line), |
| 67 | Function: ent.Func, |
| 68 | }), |
| 69 | ) |
| 70 | |
| 71 | if len(ent.LoggerNames) > 0 { |
| 72 | e = append(e, slog.F("logging.googleapis.com/operation", &loggingpb.LogEntryOperation{ |
| 73 | Producer: strings.Join(ent.LoggerNames, "."), |
| 74 | })) |
| 75 | } |
| 76 | |
| 77 | if ent.SpanContext.IsValid() { |
| 78 | e = append(e, |
| 79 | slog.F("logging.googleapis.com/trace", s.traceField(ent.SpanContext.TraceID())), |
| 80 | slog.F("logging.googleapis.com/spanId", ent.SpanContext.SpanID().String()), |
| 81 | slog.F("logging.googleapis.com/trace_sampled", ent.SpanContext.IsSampled()), |
| 82 | ) |
| 83 | } |
| 84 | |
| 85 | e = append(e, ent.Fields...) |
| 86 | |
| 87 | buf, _ := json.Marshal(e) |
| 88 | |
| 89 | buf = append(buf, '\n') |
| 90 | s.w.Write("slogstackdriver", buf) |
| 91 | } |
| 92 | |
| 93 | func (s stackdriverSink) Sync() { |
| 94 | s.w.Sync("stackdriverSink") |
nothing calls this directly
no test coverage detected