Skip to content

Commit

Permalink
Implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
maguro committed Apr 3, 2024
1 parent 32f58bf commit 384d190
Show file tree
Hide file tree
Showing 10 changed files with 886 additions and 4 deletions.
166 changes: 166 additions & 0 deletions attr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// Copyright 2024 The original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gslog

import (
"bytes"
"encoding/json"
"log/slog"

Check failure on line 20 in attr.go

View workflow job for this annotation

GitHub Actions / tests (tests, 1.20)

package log/slog is not in GOROOT (/opt/hostedtoolcache/go/1.20.14/x64/src/log/slog)

Check failure on line 20 in attr.go

View workflow job for this annotation

GitHub Actions / tests (tests, 1.20)

package log/slog is not in GOROOT (/opt/hostedtoolcache/go/1.20.14/x64/src/log/slog)

Check failure on line 20 in attr.go

View workflow job for this annotation

GitHub Actions / tests (tests, 1.20)

package log/slog is not in GOROOT (/opt/hostedtoolcache/go/1.20.14/x64/src/log/slog)
"sync"
"time"

structpb "github.com/golang/protobuf/ptypes/struct"
spb "google.golang.org/protobuf/types/known/structpb"
)

var (
noopAttrMapper AttrMapper = func(_ []string, a slog.Attr) slog.Attr {
return a
}

timePool = sync.Pool{
New: func() any {
b := make([]byte, 0, len(time.RFC3339Nano))
return &b
},
}
)

// AttrMapper is called to rewrite each non-group attribute before it is logged.
// The attribute's value has been resolved (see [Value.Resolve]).
// If replaceAttr returns a zero Attr, the attribute is discarded.
//
// The built-in attributes with keys "time", "level", "source", and "msg"
// are passed to this function, except that time is omitted
// if zero, and source is omitted if addSource is false.
//
// The first argument is a list of currently open groups that contain the
// Attr. It must not be retained or modified. replaceAttr is never called
// for Group attributes, only their contents. For example, the attribute
// list
//
// Int("a", 1), Group("g", Int("b", 2)), Int("c", 3)
//
// results in consecutive calls to replaceAttr with the following arguments:
//
// nil, Int("a", 1)
// []string{"g"}, Int("b", 2)
// nil, Int("c", 3)
//
// AttrMapper can be used to change the default keys of the built-in
// attributes, convert types (for example, to replace a `time.Time` with the
// integer seconds since the Unix epoch), sanitize personal information, or
// remove attributes from the output.
type AttrMapper func(groups []string, a slog.Attr) slog.Attr

func decorateWith(p *structpb.Struct, a slog.Attr) {
a.Value.Resolve()
val, ok := valToStruct(a.Value)
if !ok {
return
}
p.Fields[a.Key] = val
}

func valToStruct(v slog.Value) (val *structpb.Value, ok bool) {
switch v.Kind() {
case slog.KindString:
return &structpb.Value{Kind: &structpb.Value_StringValue{StringValue: v.String()}}, true
case slog.KindInt64:
return &structpb.Value{Kind: &structpb.Value_NumberValue{NumberValue: float64(v.Int64())}}, true
case slog.KindUint64:
return &structpb.Value{Kind: &structpb.Value_NumberValue{NumberValue: float64(v.Uint64())}}, true
case slog.KindFloat64:
return &structpb.Value{Kind: &structpb.Value_NumberValue{NumberValue: v.Float64()}}, true
case slog.KindBool:
return &structpb.Value{Kind: &structpb.Value_BoolValue{BoolValue: v.Bool()}}, true
case slog.KindDuration:
return &structpb.Value{Kind: &structpb.Value_NumberValue{NumberValue: float64(v.Duration())}}, true
case slog.KindTime:
ptr := timePool.Get().(*[]byte)
buf := *ptr
buf = buf[0:0]
defer func() {
*ptr = buf
timePool.Put(ptr)
}()
buf = append(buf, byte('"'))
buf = v.Time().AppendFormat(buf, time.RFC3339Nano)
buf = append(buf, byte('"'))
return &structpb.Value{Kind: &structpb.Value_StringValue{StringValue: string(buf)}}, true
case slog.KindGroup:
p2 := &structpb.Struct{Fields: make(map[string]*spb.Value)}
for _, b := range v.Group() {
decorateWith(p2, b)
}
return &structpb.Value{Kind: &structpb.Value_StructValue{StructValue: p2}}, true
case slog.KindAny:
a := v.Any()

// if value is an error, but not a JSON marshaller, return error
_, jm := a.(json.Marshaler)
if err, ok := a.(error); ok && !jm {
return &structpb.Value{Kind: &structpb.Value_StringValue{StringValue: err.Error()}}, true
}

// value may be simply mappable to a structpb.Value.
if nv, err := spb.NewValue(a); err == nil {
return nv, true
}

// try converting to a JSON object
return asJson(a)
default:
return nil, false
}
}

func fromPath(p *structpb.Struct, path []string) *structpb.Struct {
for _, k := range path {
p = p.Fields[k].GetStructValue()
}
if p.Fields == nil {
p.Fields = make(map[string]*structpb.Value)
}
return p
}

func asJson(a any) (*structpb.Value, bool) {
a, err := toJson(a)
if err != nil {
return nil, false
}

if nv, err := spb.NewValue(a); err == nil {
return nv, true
}

return nil, false
}

func toJson(a any) (any, error) {
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
if err := enc.Encode(a); err != nil {
return nil, err
}

var result any
if err := json.Unmarshal(buf.Bytes(), &result); err != nil {
return nil, err
}

return result, nil
}
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ go 1.22

require (
cloud.google.com/go/logging v1.9.0
github.com/golang/protobuf v1.5.3
github.com/onsi/ginkgo/v2 v2.17.1
github.com/onsi/gomega v1.32.0
github.com/stretchr/testify v1.9.0
go.opentelemetry.io/otel/trace v1.24.0
google.golang.org/protobuf v1.33.0
)

require (
Expand All @@ -18,14 +21,14 @@ require (
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/oauth2 v0.13.0 // indirect
Expand All @@ -39,6 +42,5 @@ require (
google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect
google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
12 changes: 10 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,16 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
Expand Down Expand Up @@ -82,6 +84,10 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
Expand Down Expand Up @@ -158,6 +164,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
Expand Down
Loading

0 comments on commit 384d190

Please sign in to comment.