Skip to content

Commit

Permalink
feat: change librariy for loki client
Browse files Browse the repository at this point in the history
  • Loading branch information
samber committed Oct 24, 2023
1 parent 44caf28 commit ccaf6b4
Show file tree
Hide file tree
Showing 9 changed files with 2,008 additions and 137 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ jobs:
- name: Remove xxx_test.go files
run: rm -rf *_test.go ./examples ./images

- name: Set library version in version.go
run: sed -i 's/VERSION/${{ inputs.semver }}/g' version.go

# cleanup test dependencies
- name: Cleanup dependencies
run: go mod tidy
Expand Down
33 changes: 24 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,27 @@ GoDoc: [https://pkg.go.dev/github.com/samber/slog-loki/v2](https://pkg.go.dev/gi
type Option struct {
// log level (default: debug)
Level slog.Leveler

// loki endpoint
Endpoint string
// log batching
BatchWait time.Duration
BatchEntriesNumber int

// loki
Client *loki.Client

// optional: customize webhook event builder
Converter Converter

// optional: see slog.HandlerOptions
AddSource bool
ReplaceAttr func(groups []string, a slog.Attr) slog.Attr
}
```

Attributes will be injected in log payload.

Attributes added to records are not accepted.
Other global parameters:

```go
slogzerolog.SourceKey = "source"
slogzerolog.ErrorKeys = []string{"error", "err"}
```

### Example

Expand All @@ -82,9 +91,12 @@ import (
)

func main() {
endpoint := "http://localhost:3100"
// setup loki client
config, _ := loki.NewDefaultConfig("http://localhost:3100")
config.TenantID = "xyz"
client, _ := loki.New(config)

logger := slog.New(slogloki.Option{Level: slog.LevelDebug, Endpoint: endpoint}.NewLokiHandler())
logger := slog.New(slogloki.Option{Level: slog.LevelDebug, Client: client}.NewLokiHandler())
logger = logger.
With("environment", "dev").
With("release", "v1.0.0")
Expand All @@ -94,6 +106,9 @@ func main() {

// log user signup
logger.Info("user registration")

// stop loki client and purge buffers
client.Stop()
}
```

Expand Down
81 changes: 40 additions & 41 deletions converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,54 @@ package slogloki

import (
"fmt"
"strconv"
"strings"

"log/slog"
"strconv"

"github.com/prometheus/common/model"
slogcommon "github.com/samber/slog-common"
)

func attrToLabelMap(base string, attrs []slog.Attr, labels *map[string]string) {
for i := range attrs {
attrToValue(base, attrs[i], labels)
}
}
var SourceKey = "source"
var ErrorKeys = []string{"error", "err"}

type Converter func(addSource bool, replaceAttr func(groups []string, a slog.Attr) slog.Attr, loggerAttr []slog.Attr, groups []string, record *slog.Record) model.LabelSet

func attrToValue(base string, attr slog.Attr, labels *map[string]string) {
k := attr.Key
v := attr.Value
kind := v.Kind()

switch kind {
case slog.KindAny:
(*labels)[base+k] = slogcommon.AnyValueToString(v)
case slog.KindLogValuer:
(*labels)[base+k] = slogcommon.AnyValueToString(v)
case slog.KindGroup:
attrToLabelMap(base+k+".", v.Group(), labels)
case slog.KindInt64:
(*labels)[base+k] = fmt.Sprintf("%d", v.Int64())
case slog.KindUint64:
(*labels)[base+k] = fmt.Sprintf("%d", v.Uint64())
case slog.KindFloat64:
(*labels)[base+k] = fmt.Sprintf("%f", v.Float64())
case slog.KindString:
(*labels)[base+k] = v.String()
case slog.KindBool:
(*labels)[base+k] = strconv.FormatBool(v.Bool())
case slog.KindDuration:
(*labels)[base+k] = v.Duration().String()
case slog.KindTime:
(*labels)[base+k] = v.Time().UTC().String()
default:
(*labels)[base+k] = slogcommon.AnyValueToString(v)
func DefaultConverter(addSource bool, replaceAttr func(groups []string, a slog.Attr) slog.Attr, loggerAttr []slog.Attr, groups []string, record *slog.Record) model.LabelSet {
// aggregate all attributes
attrs := slogcommon.AppendRecordAttrsToAttrs(loggerAttr, groups, record)

// developer formatters
attrs = slogcommon.ReplaceError(attrs, ErrorKeys...)
if addSource {
attrs = append(attrs, slogcommon.Source(SourceKey, record))
}
attrs = slogcommon.ReplaceAttrs(replaceAttr, []string{}, attrs...)
attrs = append(attrs, slog.String("level", record.Level.String()))

// handler formatter
output := slogcommon.AttrsToMap(attrs...)

labelSet := model.LabelSet{}
flatten("", output, labelSet)

return labelSet
}

func mapToLabels(input map[string]string) string {
labelsList := []string{}
for k, v := range input {
labelsList = append(labelsList, fmt.Sprintf(`%s="%s"`, k, v))
// https://stackoverflow.com/questions/64419565/how-to-efficiently-flatten-a-map
func flatten(prefix string, src map[string]any, dest model.LabelSet) {
if len(prefix) > 0 {
prefix += "."
}
for k, v := range src {
switch child := v.(type) {
case map[string]any:
flatten(prefix+k, child, dest)
case []any:
for i := 0; i < len(child); i++ {
dest[model.LabelName(prefix+k+"."+strconv.Itoa(i))] = model.LabelValue(fmt.Sprintf("%v", child[i]))
}
default:
dest[model.LabelName(prefix+k)] = model.LabelValue(fmt.Sprintf("%v", v))
}
}
return fmt.Sprintf(`{%s}`, strings.Join(labelsList, ", "))
}
9 changes: 7 additions & 2 deletions example/example.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package main

import (
"github.com/grafana/loki-client-go/loki"
slogloki "github.com/samber/slog-loki/v2"

"log/slog"
)

func main() {
endpoint := "http://localhost:3100"
config, _ := loki.NewDefaultConfig("http://localhost:3100")
config.TenantID = "xyz"
client, _ := loki.New(config)

logger := slog.New(slogloki.Option{Level: slog.LevelDebug, Endpoint: endpoint}.NewLokiHandler())
logger := slog.New(slogloki.Option{Level: slog.LevelDebug, Client: client}.NewLokiHandler())
logger = logger.With("release", "v1.0.0")

logger.Error("A message")

client.Stop()
}
36 changes: 35 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,50 @@ module github.com/samber/slog-loki/v2
go 1.21

require (
github.com/afiskon/promtail-client v0.0.0-20190305142237-506f3f921e9c
github.com/grafana/loki-client-go v0.0.0-20230116142646-e7494d0ef70c
github.com/prometheus/common v0.34.0
github.com/samber/slog-common v0.11.0
go.uber.org/goleak v1.2.1
)

require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dennwc/varint v1.0.0 // indirect
github.com/go-kit/kit v0.10.0 // indirect
github.com/go-kit/log v0.2.0 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/grafana/regexp v0.0.0-20220304095617-2e8d9baf4ac2 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.12.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/prometheus/prometheus v0.35.0 // indirect
github.com/samber/lo v1.38.1 // indirect
github.com/stretchr/testify v1.8.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
golang.org/x/net v0.0.0-20220325170049-de3da57026de // indirect
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect
golang.org/x/sys v0.1.0 // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb // indirect
google.golang.org/grpc v1.45.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading

0 comments on commit ccaf6b4

Please sign in to comment.