Compare commits

...

23 Commits

Author SHA1 Message Date
Jiekun
6fc1172910 poc: [jaeger] log debug 2025-04-17 18:53:31 +08:00
Jiekun
87c1cfdf0d poc: [jaeger] fix tag filter 2025-04-17 18:49:42 +08:00
Ted Possible
921850f7c9 Optimizes with bytes buffer pool
Removes writing VType to logs db and instead uses string if vType is not defined
2025-03-24 12:04:41 -07:00
Jiekun
7c04b07b16 poc: [jaeger] update query for FindTraceIDs 2025-03-19 14:20:13 +08:00
Jiekun
57ac1302de poc: [jaeger] skip empty fields for span for get trace 2025-03-09 16:34:20 +08:00
Jiekun
f6854855b0 poc: [jaeger] skip empty fields for span 2025-03-09 16:26:01 +08:00
Jiekun
c65a4f1ec9 poc: [jaeger] use field instad of json msg 2025-03-09 16:10:05 +08:00
Jiekun
cdcf5a8061 poc: [jaeger] add time filter to FindTraces 2025-03-04 14:17:50 +08:00
Jiekun
1cfd9e05f2 poc: [jaeger] adjust query execution for get traces 2025-03-04 11:29:07 +08:00
Jiekun
fd491b3cc2 poc: [jaeger] add debug logging 2025-03-03 11:12:11 +08:00
Jiekun
aab4de6066 poc: [jaeger] fix dependency reader 2025-02-28 16:27:29 +08:00
Ted Possible
58ba8569e2 Fixes some linting issues
Fixes a bug with columns value being overwritten causing incomplete data in spanRows - clone the string instead
2025-02-27 08:31:49 -08:00
Jiekun
b302a44302 poc: [jaeger] add | limit 2025-02-28 00:22:21 +08:00
Jiekun
9a8f5037a0 poc: [jaeger] update reader and server to fix the type convertion erro 2025-02-28 00:11:52 +08:00
Ted Possible
2aa883a1bd Fixes some linting issues
Fixes a bug with columns value being overwritten causing incomplete data in spanRows - clone the string instead
2025-02-24 12:45:54 -08:00
Jiekun
67f5d0aec9 add model.pb.go 2025-02-24 23:57:35 +08:00
Jiekun
247ffff910 poc: [jaeger] add basic impl without testing 2025-02-11 19:44:49 +08:00
Jiekun
df2c973e50 feature: [jaeger poc] add test grpc client 2025-01-29 00:13:07 +08:00
Ted Possible
615d719fac Fixed panic with SpanWriterPluginServer from a copy/paste mistake that was accessing tags instead of processTags
Fixed some unkeyed errors in `make check-all`
2025-01-27 17:47:16 -08:00
Ted Possible
6028ca11de Restored vendor changes for metricsql 2025-01-25 14:54:16 -08:00
Ted Possible
7202ce8a5b Added GetJaegerCommonParams to bypass the need for an http request object for GetCommonParams 2025-01-25 14:41:14 -08:00
Jiekun
2267070297 feature: [jaeger] init vlogs jaeger grpc api 2 2025-01-24 11:39:30 +08:00
Jiekun
1b5b234804 feature: [jaeger] init vlogs jaeger grpc api 2025-01-24 11:34:49 +08:00
650 changed files with 75164 additions and 20611 deletions

View File

@@ -40,6 +40,40 @@ type CommonParams struct {
DebugRemoteAddr string
}
// GetJaegerCommonParams returns CommonParams for Jaeger.
func GetJaegerCommonParams() (*CommonParams, error) {
// Extract tenantID
var tenantID = logstorage.TenantID{
AccountID: 0,
ProjectID: 0,
}
timeField := "_time"
msgFields := []string{"_msg"}
streamFields := []string{"_stream"}
ignoreFields := []string{"_ignore"}
extraFields := []logstorage.Field{}
debug := false
debugRequestURI := ""
debugRemoteAddr := ""
cp := &CommonParams{
TenantID: tenantID,
TimeField: timeField,
MsgFields: msgFields,
StreamFields: streamFields,
IgnoreFields: ignoreFields,
ExtraFields: extraFields,
Debug: debug,
DebugRequestURI: debugRequestURI,
DebugRemoteAddr: debugRemoteAddr,
}
return cp, nil
}
// GetCommonParams returns CommonParams from r.
func GetCommonParams(r *http.Request) (*CommonParams, error) {
// Extract tenantID

View File

@@ -0,0 +1,45 @@
package jaeger
import (
"fmt"
"github.com/jaegertracing/jaeger/storage/dependencystore"
"github.com/jaegertracing/jaeger/storage/spanstore"
"log"
"net"
jaeger2 "github.com/VictoriaMetrics/VictoriaMetrics/app/vlselect/jaeger"
"github.com/jaegertracing/jaeger/plugin/storage/grpc/shared"
"google.golang.org/grpc"
)
// MustInit - init for Jaeger gRPC storage backend
func MustInit() {
lis, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", 17271))
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
var opts []grpc.ServerOption
grpcServer := grpc.NewServer(opts...)
handler := shared.NewGRPCHandler(&shared.GRPCHandlerStorageImpl{
SpanReader: func() spanstore.Reader { return &jaeger2.SpanReaderPluginServer{} },
SpanWriter: func() spanstore.Writer { return &SpanWriterPluginServer{} },
DependencyReader: func() dependencystore.Reader { return &jaeger2.SpanReaderPluginServer{} },
ArchiveSpanReader: func() spanstore.Reader { return nil },
ArchiveSpanWriter: func() spanstore.Writer { return nil },
StreamingSpanWriter: func() spanstore.Writer { return nil },
})
//proto.RegisterSpanWriterPluginServer(grpcServer, &SpanWriterPluginServer{})
//proto.RegisterSpanReaderPluginServer(grpcServer, &jaeger2.SpanReaderPluginServer{})
err = handler.Register(grpcServer)
if err != nil {
panic("unable to register Jaeger gRPC handler: " + err.Error())
}
go grpcServer.Serve(lis)
}
// MustStop - stop for Jaeger gRPC storage backend
func MustStop() {}

View File

@@ -0,0 +1,44 @@
package jaeger
import (
"context"
"fmt"
"github.com/jaegertracing/jaeger/model"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/jaeger"
)
// A SpanWriterPluginServer represents plugin Jaeger interface to write gRPC storage backend
type SpanWriterPluginServer struct {
}
var bbufPool bytesutil.ByteBufferPool
// WriteSpan writes spans
func (s *SpanWriterPluginServer) WriteSpan(ctx context.Context, span *model.Span) error {
if span == nil {
return fmt.Errorf("span not found")
}
cp, err := insertutils.GetJaegerCommonParams()
if err != nil {
return err
}
lmp := cp.NewLogMessageProcessor("jaeger")
defer lmp.MustClose()
// bytes buf here
bbuf := bbufPool.Get()
defer bbufPool.Put(bbuf)
bbuf.Reset()
fields, streamFields, err := jaeger.SpanToFields(span)
lmp.AddRow(span.StartTime.UnixNano(), fields, streamFields)
// bytes bf clear
return nil
}
func (s *SpanWriterPluginServer) Close() error {
return nil
}

View File

@@ -0,0 +1,42 @@
package main
import (
"context"
"fmt"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/jaeger/proto"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"testing"
)
func newSpanReaderPluginClient(t *testing.T) proto.SpanReaderPluginClient {
conn, err := grpc.NewClient(fmt.Sprintf("0.0.0.0:%d", 17271), grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
t.Fatalf("cannot connect to server: %v", err)
}
return proto.NewSpanReaderPluginClient(conn)
}
func newSpanWriterPluginClient(t *testing.T) proto.SpanWriterPluginClient {
conn, err := grpc.NewClient(fmt.Sprintf("0.0.0.0:%d", 17271), grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
t.Fatalf("cannot connect to server: %v", err)
}
return proto.NewSpanWriterPluginClient(conn)
}
func TestSpanWriter(t *testing.T) {
// This is NOT a unit test. Please run the VictoriaLogs before executing this test.
client := newSpanWriterPluginClient(t)
req := &proto.WriteSpanRequest{}
resp, err := client.WriteSpan(context.Background(), req)
fmt.Println(resp, err)
}
func TestSpanReaderGetOperations(t *testing.T) {
// This is NOT a unit test. Please run the VictoriaLogs before executing this test.
client := newSpanReaderPluginClient(t)
req := &proto.GetOperationsRequest{}
resp, err := client.GetOperations(context.Background(), req)
fmt.Println(resp, err)
}

View File

@@ -2,6 +2,7 @@ package vlinsert
import (
"fmt"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/jaeger"
"net/http"
"strings"
@@ -17,11 +18,13 @@ import (
// Init initializes vlinsert
func Init() {
syslog.MustInit()
jaeger.MustInit()
}
// Stop stops vlinsert
func Stop() {
syslog.MustStop()
jaeger.MustStop()
}
// RequestHandler handles insert requests for VictoriaLogs

View File

@@ -0,0 +1,293 @@
package jaeger
import (
"context"
"fmt"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/jaeger"
"strings"
"sync"
"time"
"github.com/jaegertracing/jaeger/model"
"github.com/jaegertracing/jaeger/storage/spanstore"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vlstorage"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage"
)
// A SpanReaderPluginServer represents a Jaeger interface to read from gRPC storage backend
type SpanReaderPluginServer struct{}
type row struct {
timestamp int64
fields []logstorage.Field
}
func (s *SpanReaderPluginServer) GetTrace(ctx context.Context, traceID model.TraceID) (*model.Trace, error) {
start := time.Now()
defer func() {
logger.Infof("GetTrace finished in %dms", time.Since(start).Milliseconds())
}()
qStr := fmt.Sprintf("%s:%s", jaeger.TraceID, traceID.String())
q, err := logstorage.ParseQueryAtTimestamp(qStr, time.Now().UnixNano())
if err != nil {
return nil, fmt.Errorf("cannot parse query [%s]: %s", qStr, err)
}
var rows []row
var rowsLock sync.Mutex
writeBlock := func(_ uint, timestamps []int64, columns []logstorage.BlockColumn) {
clonedColumnNames := make([]string, len(columns))
for i, c := range columns {
clonedColumnNames[i] = strings.Clone(c.Name)
}
for i, timestamp := range timestamps {
fields := make([]logstorage.Field, len(columns))
for j := range columns {
if columns[j].Values[i] != "" {
fields = append(fields, logstorage.Field{Name: clonedColumnNames[j], Value: strings.Clone(columns[j].Values[i])})
}
}
rowsLock.Lock()
rows = append(rows, row{
timestamp: timestamp,
fields: fields,
})
rowsLock.Unlock()
}
}
logger.Infof("GetTrace query: %s", q.String())
if err = vlstorage.RunQuery(context.TODO(), []logstorage.TenantID{{AccountID: 0, ProjectID: 0}}, q, writeBlock); err != nil {
return nil, err
}
spans := make([]*model.Span, 0, len(rows))
for i := range rows {
sp, err := jaeger.FieldsToSpan(rows[i].fields)
if err != nil {
logger.Errorf("cannot unmarshal log fields [%v] to span: %s", rows[i].fields, err)
continue
}
spans = append(spans, sp)
}
trace := &model.Trace{
Spans: spans,
}
return trace, nil
}
func (s *SpanReaderPluginServer) GetServices(ctx context.Context) ([]string, error) {
start := time.Now()
defer func() {
logger.Infof("GetServices finished in %dms", time.Since(start).Milliseconds())
}()
qStr := "*"
q, err := logstorage.ParseQueryAtTimestamp(qStr, time.Now().UnixNano())
if err != nil {
return nil, fmt.Errorf("cannot parse query [%s]: %s", qStr, err)
}
q.AddTimeFilter(0, time.Now().UnixNano())
logger.Infof("GetServices StreamFieldValues query: %s", q.String())
serviceHits, err := vlstorage.GetStreamFieldValues(ctx, []logstorage.TenantID{{AccountID: 0, ProjectID: 0}}, q, jaeger.ProcessServiceName, uint64(1000))
if err != nil {
return nil, err
}
serviceList := make([]string, 0)
for i := range serviceHits {
serviceList = append(serviceList, serviceHits[i].Value)
}
return serviceList, nil
}
func (s *SpanReaderPluginServer) GetOperations(ctx context.Context, req spanstore.OperationQueryParameters) ([]spanstore.Operation, error) {
start := time.Now()
defer func() {
logger.Infof("GetOperations finished in %dms", time.Since(start).Milliseconds())
}()
qStr := fmt.Sprintf("_stream:{%s=\"%s\"}", jaeger.ProcessServiceName, req.ServiceName) // todo spankind filter
q, err := logstorage.ParseQueryAtTimestamp(qStr, time.Now().UnixNano())
if err != nil {
return nil, fmt.Errorf("cannot parse query [%s]: %s", qStr, err)
}
logger.Infof("GetOperations StreamFieldValues query: %s", q.String())
operationHits, err := vlstorage.GetStreamFieldValues(ctx, []logstorage.TenantID{{AccountID: 0, ProjectID: 0}}, q, jaeger.OperationName, uint64(1000))
if err != nil {
return nil, err
}
operationList := make([]spanstore.Operation, 0)
for i := range operationHits {
operationList = append(operationList, spanstore.Operation{Name: operationHits[i].Value})
}
return operationList, nil
}
func (s *SpanReaderPluginServer) FindTraces(ctx context.Context, query *spanstore.TraceQueryParameters) ([]*model.Trace, error) {
start := time.Now()
defer func() {
logger.Infof("FindTraces finished in %dms", time.Since(start).Milliseconds())
}()
traceIDs, err := s.FindTraceIDs(ctx, query)
if err != nil {
return nil, err
}
if len(traceIDs) == 0 {
return nil, nil
}
traceIDStrList := make([]string, 0, len(traceIDs))
for _, traceID := range traceIDs {
traceIDStrList = append(traceIDStrList, traceID.String())
}
qStr := fmt.Sprintf(jaeger.TraceID+":in(%s)", strings.Join(traceIDStrList, ","))
q, err := logstorage.ParseQueryAtTimestamp(qStr, time.Now().UnixNano())
if err != nil {
return nil, fmt.Errorf("cannot parse query [%s]: %s", qStr, err)
}
q.AddTimeFilter(query.StartTimeMin.UnixNano(), query.StartTimeMax.UnixNano())
var rows []row
var rowsLock sync.Mutex
writeBlock := func(_ uint, timestamps []int64, columns []logstorage.BlockColumn) {
clonedColumnNames := make([]string, len(columns))
for i, c := range columns {
clonedColumnNames[i] = strings.Clone(c.Name)
}
for i, timestamp := range timestamps {
fields := make([]logstorage.Field, 0, len(columns))
for j := range columns {
if columns[j].Values[i] != "" {
fields = append(fields, logstorage.Field{Name: clonedColumnNames[j], Value: strings.Clone(columns[j].Values[i])})
}
}
rowsLock.Lock()
rows = append(rows, row{
timestamp: timestamp,
fields: fields,
})
rowsLock.Unlock()
}
}
logger.Infof("FindTraces query: %s", q.String())
if err = vlstorage.RunQuery(context.TODO(), []logstorage.TenantID{{AccountID: 0, ProjectID: 0}}, q, writeBlock); err != nil {
return nil, err
}
tracesMap := make(map[string]*model.Trace)
traces := make([]*model.Trace, len(traceIDs), len(traceIDs))
for i := range traceIDs {
traces[i] = &model.Trace{}
tracesMap[traceIDs[i].String()] = traces[i]
}
for i := range rows {
sp, err := jaeger.FieldsToSpan(rows[i].fields)
if err != nil {
logger.Errorf("cannot unmarshal log fields [%v] to span: %s", rows[i].fields, err)
continue
}
tracesMap[sp.TraceID.String()].Spans = append(tracesMap[sp.TraceID.String()].Spans, sp)
}
return traces, nil
}
func (s *SpanReaderPluginServer) FindTraceIDs(ctx context.Context, query *spanstore.TraceQueryParameters) ([]model.TraceID, error) {
start := time.Now()
defer func() {
logger.Infof("FindTraceIDs finished in %dms", time.Since(start).Milliseconds())
}()
qStr := ""
if svcName := query.ServiceName; svcName != "" {
qStr += fmt.Sprintf("AND _stream:{"+jaeger.ProcessServiceName+"=\"%s\"} ", svcName)
}
if operationName := query.OperationName; operationName != "" {
qStr += fmt.Sprintf("AND _stream:{"+jaeger.OperationName+"=\"%s\"} ", operationName)
}
if tags := query.Tags; len(tags) > 0 {
for k, v := range tags {
qStr += fmt.Sprintf(`AND "`+jaeger.TagKey+`":=%s `, k, v)
}
}
if durationMin := query.DurationMin; durationMin > 0 {
qStr += fmt.Sprintf("AND "+jaeger.Duration+":>%d ", durationMin.Nanoseconds())
}
if durationMax := query.DurationMax; durationMax > 0 {
qStr += fmt.Sprintf("AND duration:<%d ", durationMax.Nanoseconds())
}
qStr = strings.TrimLeft(qStr+" | last 1 by (_time) partition by ("+jaeger.TraceID+") | fields _time, "+jaeger.TraceID+" | sort by (_time) desc", "AND ")
logger.Infof("FindTraceIDs query debug: %s", qStr)
q, err := logstorage.ParseQueryAtTimestamp(qStr, query.StartTimeMax.UnixNano())
if err != nil {
return nil, fmt.Errorf("cannot parse query [%s]: %s", qStr, err)
}
q.AddPipeLimit(uint64(query.NumTraces))
traceIDSs, err := findTraceIDsSplitTimeRange(q, query.StartTimeMin, query.StartTimeMax, query.NumTraces)
if err != nil {
return nil, err
}
traceIDList := make([]model.TraceID, 0, query.NumTraces)
for _, v := range traceIDSs {
tid, err := model.TraceIDFromString(v)
if err != nil {
return nil, fmt.Errorf("cannot unmarshal [%s]: %s", v, err)
}
traceIDList = append(traceIDList, tid)
}
return traceIDList, nil
}
// findTraceIDsSplitTimeRange try to search from the nearest time range of the end time.
// if the result already met requirement of `limit`, return.
// otherwise, amplify the time range to 5x and search again, until the start time exceed the input.
func findTraceIDsSplitTimeRange(q *logstorage.Query, startTime, endTime time.Time, limit int) ([]string, error) {
step := time.Minute
startTimeCurrent := endTime.Add(-step)
traceIDList := make([]string, 0, 10)
writeBlock := func(_ uint, _ []int64, columns []logstorage.BlockColumn) {
for i := range columns {
if columns[i].Name == "trace_id" {
for _, v := range columns[i].Values {
traceIDList = append(traceIDList, v)
}
}
}
}
for startTimeCurrent.After(startTime) {
qClone := q.CloneWithTimeFilter(endTime.UnixNano(), startTimeCurrent.UnixNano(), endTime.UnixNano())
logger.Infof("FindTraces query: %s", qClone.String())
if err := vlstorage.RunQuery(context.TODO(), []logstorage.TenantID{{AccountID: 0, ProjectID: 0}}, qClone, writeBlock); err != nil {
return nil, err
}
if len(traceIDList) == limit {
return traceIDList, nil
}
traceIDList = traceIDList[:0]
step *= 5
startTimeCurrent = startTimeCurrent.Add(-step)
}
// one last try with input time range
qClone := q.CloneWithTimeFilter(endTime.UnixNano(), startTimeCurrent.UnixNano(), endTime.UnixNano())
logger.Infof("FindTraces query: %s", qClone.String())
if err := vlstorage.RunQuery(context.TODO(), []logstorage.TenantID{{AccountID: 0, ProjectID: 0}}, qClone, writeBlock); err != nil {
return nil, err
}
return traceIDList, nil
}
func (s *SpanReaderPluginServer) GetDependencies(ctx context.Context, endTs time.Time, lookback time.Duration) ([]model.DependencyLink, error) {
return []model.DependencyLink{}, nil
}

41
go.mod
View File

@@ -30,11 +30,12 @@ require (
github.com/gogo/protobuf v1.3.2
github.com/golang/snappy v0.0.4
github.com/google/go-cmp v0.6.0
github.com/googleapis/gax-go/v2 v2.14.1
github.com/googleapis/gax-go/v2 v2.13.0
github.com/influxdata/influxdb v1.11.8
github.com/jaegertracing/jaeger v1.55.0
github.com/klauspost/compress v1.17.11
github.com/mattn/go-isatty v0.0.20
github.com/prometheus/prometheus v0.301.0
github.com/prometheus/prometheus v0.54.1
github.com/urfave/cli/v2 v2.27.5
github.com/valyala/fastjson v1.6.4
github.com/valyala/fastrand v1.1.0
@@ -45,16 +46,17 @@ require (
golang.org/x/net v0.34.0
golang.org/x/oauth2 v0.25.0
golang.org/x/sys v0.29.0
google.golang.org/api v0.216.0
google.golang.org/api v0.195.0
google.golang.org/grpc v1.65.0
gopkg.in/yaml.v2 v2.4.0
)
require (
cloud.google.com/go v0.118.0 // indirect
cloud.google.com/go/auth v0.14.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect
cloud.google.com/go v0.115.1 // indirect
cloud.google.com/go/auth v0.9.1 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect
cloud.google.com/go/compute/metadata v0.6.0 // indirect
cloud.google.com/go/iam v1.3.1 // indirect
cloud.google.com/go/iam v1.2.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 // indirect
github.com/VividCortex/ewma v1.2.0 // indirect
@@ -81,62 +83,69 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dennwc/varint v1.0.0 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.32.3 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-plugin v1.6.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.20.5 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.61.0 // indirect
github.com/prometheus/common/sigv4 v0.1.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/prometheus/sigv4 v0.1.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/collector/pdata v1.23.0 // indirect
go.opentelemetry.io/collector/pdata v1.14.1 // indirect
go.opentelemetry.io/collector/semconv v0.117.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.58.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect
go.opentelemetry.io/otel v1.33.0 // indirect
go.opentelemetry.io/otel/metric v1.33.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.33.0 // indirect
go.opentelemetry.io/otel/sdk v1.33.0 // indirect
go.opentelemetry.io/otel/trace v1.33.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/goleak v1.3.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.9.0 // indirect
google.golang.org/genproto v0.0.0-20250106144421-5f5ef82da422 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 // indirect
google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 // indirect
google.golang.org/grpc v1.69.2 // indirect
google.golang.org/protobuf v1.36.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apimachinery v0.32.0 // indirect

3026
go.sum

File diff suppressed because it is too large Load Diff

515
lib/jaeger/fields.go Normal file
View File

@@ -0,0 +1,515 @@
package jaeger
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
"github.com/jaegertracing/jaeger/model"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage"
)
// define the label name for span attributes
const (
// attributes that can be stored in a single field.
TraceID string = "trace_id"
SpanID string = "span_id"
OperationName string = "operation_name"
Flags string = "flags"
StartTime string = "start_time"
EndTime string = "end_time"
Duration string = "duration"
ProcessID string = "process_id"
ProcessServiceName string = "process_service_name"
ProcessTagKey string = "process_tag:%s"
ProcessTagVType string = "process_tag:%s:v_type"
// attributes that can be stored in a single field but does not need to be queried.
Logs string = "log"
Warnings string = "warnings"
References string = "references"
// attributes that cannot be stored in a single field.
TagKey string = "tag:%s" // e.g.: span_tag:otel.scope.name
TagVType string = "tag:%s:v_type" // e.g.: span_tag:otel.scope.name:v_type
)
func SpanToFieldsByteBuffer(bbuf *bytesutil.ByteBuffer, span *model.Span) ([]logstorage.Field, []logstorage.Field, error) {
fields := make([]logstorage.Field, 0)
fields = append(fields, logstorage.Field{Name: "_msg", Value: "span"},
logstorage.Field{Name: TraceID, Value: span.TraceID.String()},
logstorage.Field{Name: SpanID, Value: span.SpanID.String()},
logstorage.Field{Name: Flags, Value: strconv.FormatUint(uint64(span.Flags), 10)},
logstorage.Field{Name: StartTime, Value: strconv.FormatInt(span.StartTime.UnixNano(), 10)},
logstorage.Field{Name: EndTime, Value: strconv.FormatInt(span.StartTime.Add(span.Duration).UnixNano(), 10)},
logstorage.Field{Name: Duration, Value: strconv.FormatInt(span.Duration.Nanoseconds(), 10)}, logstorage.Field{Name: ProcessID, Value: span.ProcessID},
logstorage.Field{Name: ProcessServiceName, Value: span.GetProcess().GetServiceName()},
logstorage.Field{Name: OperationName, Value: span.GetOperationName()},
)
if tags := span.GetProcess().GetTags(); len(tags) > 0 {
for i := range tags {
var value string
switch tags[i].GetVType() {
case model.ValueType_STRING:
value = tags[i].GetVStr()
case model.ValueType_BOOL:
value = strconv.FormatBool(tags[i].GetVBool())
case model.ValueType_INT64:
value = strconv.FormatInt(tags[i].GetVInt64(), 10)
case model.ValueType_FLOAT64:
value = strconv.FormatFloat(tags[i].GetVFloat64(), 'f', -1, 64)
case model.ValueType_BINARY:
value = string(tags[i].GetVBinary())
}
startIdx := int64(len(bbuf.B))
bbuf.Write([]byte("process_tag:"))
bbuf.Write([]byte(tags[i].GetKey()))
fields = append(fields, logstorage.Field{Name: string(bbuf.B[startIdx:]), Value: value})
vType := int64(tags[i].GetVType())
if vType > 0 {
bbuf.Write([]byte(":v_type"))
//fields = append(fields, logstorage.Field{Name: string(bbuf.B[startIdx:]), Value: strconv.FormatInt(int64(tags[i].GetVType()), 10)})
fields = append(fields, logstorage.Field{Name: string(bbuf.B[startIdx:]), Value: "1"})
}
}
}
if len(span.Logs) > 0 {
logs, err := json.Marshal(span.Logs)
if err != nil {
return nil, nil, err
}
fields = append(fields, logstorage.Field{
Name: Logs,
Value: string(logs),
})
}
if len(span.Warnings) > 0 {
warnings, err := json.Marshal(span.Warnings)
if err != nil {
return nil, nil, err
}
fields = append(fields, logstorage.Field{
Name: Warnings,
Value: string(warnings),
})
}
if len(span.References) > 0 {
refs, err := json.Marshal(span.References)
if err != nil {
return nil, nil, err
}
fields = append(fields, logstorage.Field{
Name: References,
Value: string(refs),
})
}
tags := span.GetTags()
for i := range tags {
var value string
switch tags[i].GetVType() {
case model.ValueType_STRING:
value = tags[i].GetVStr()
case model.ValueType_BOOL:
value = strconv.FormatBool(tags[i].GetVBool())
case model.ValueType_INT64:
value = strconv.FormatInt(tags[i].GetVInt64(), 10)
case model.ValueType_FLOAT64:
value = strconv.FormatFloat(tags[i].GetVFloat64(), 'f', -1, 64)
case model.ValueType_BINARY:
value = string(tags[i].GetVBinary())
}
startIdx := int64(len(bbuf.B))
bbuf.Write([]byte("tag:"))
bbuf.Write([]byte(tags[i].GetKey()))
fields = append(fields, logstorage.Field{Name: string(bbuf.B[startIdx:]), Value: value})
vtype := int64(tags[i].GetVType())
if vtype > 0 {
bbuf.Write([]byte(":v_type"))
startVtype := int64(len(bbuf.B))
bbuf.Write([]byte(strconv.FormatInt(int64(tags[i].GetVType()), 10)))
fields = append(fields, logstorage.Field{Name: string(bbuf.B[startIdx:startVtype]), Value: string(bbuf.B[startVtype:])})
}
}
streamFields := make([]logstorage.Field, 0, 2)
streamFields = append(streamFields,
logstorage.Field{Name: ProcessServiceName, Value: span.GetProcess().GetServiceName()},
logstorage.Field{Name: OperationName, Value: span.GetOperationName()},
)
return fields, streamFields, nil
}
func SpanToFieldsStringBuilder(sb *strings.Builder, span *model.Span) ([]logstorage.Field, []logstorage.Field, error) {
fields := make([]logstorage.Field, 0)
fields = append(fields, logstorage.Field{Name: "_msg", Value: "span"},
logstorage.Field{Name: TraceID, Value: span.TraceID.String()},
logstorage.Field{Name: SpanID, Value: span.SpanID.String()},
logstorage.Field{Name: Flags, Value: strconv.FormatUint(uint64(span.Flags), 10)},
logstorage.Field{Name: StartTime, Value: strconv.FormatInt(span.StartTime.UnixNano(), 10)},
logstorage.Field{Name: EndTime, Value: strconv.FormatInt(span.StartTime.Add(span.Duration).UnixNano(), 10)},
logstorage.Field{Name: Duration, Value: strconv.FormatInt(span.Duration.Nanoseconds(), 10)}, logstorage.Field{Name: ProcessID, Value: span.ProcessID},
logstorage.Field{Name: ProcessServiceName, Value: span.GetProcess().GetServiceName()},
logstorage.Field{Name: OperationName, Value: span.GetOperationName()},
)
if tags := span.GetProcess().GetTags(); len(tags) > 0 {
for i := range tags {
var value string
switch tags[i].GetVType() {
case model.ValueType_STRING:
value = tags[i].GetVStr()
case model.ValueType_BOOL:
value = strconv.FormatBool(tags[i].GetVBool())
case model.ValueType_INT64:
value = strconv.FormatInt(tags[i].GetVInt64(), 10)
case model.ValueType_FLOAT64:
value = strconv.FormatFloat(tags[i].GetVFloat64(), 'f', -1, 64)
case model.ValueType_BINARY:
value = string(tags[i].GetVBinary())
}
sb.WriteString("process_tag:")
sb.WriteString(tags[i].GetKey())
var f1 = logstorage.Field{Name: sb.String(), Value: value}
sb.WriteString(":v_type")
var f2 = logstorage.Field{Name: sb.String(), Value: strconv.FormatInt(int64(tags[i].GetVType()), 10)}
sb.Reset()
fields = append(fields, f1, f2)
}
}
if len(span.Logs) > 0 {
logs, err := json.Marshal(span.Logs)
if err != nil {
return nil, nil, err
}
fields = append(fields, logstorage.Field{
Name: Logs,
Value: string(logs),
})
}
if len(span.Warnings) > 0 {
warnings, err := json.Marshal(span.Warnings)
if err != nil {
return nil, nil, err
}
fields = append(fields, logstorage.Field{
Name: Warnings,
Value: string(warnings),
})
}
if len(span.References) > 0 {
refs, err := json.Marshal(span.References)
if err != nil {
return nil, nil, err
}
fields = append(fields, logstorage.Field{
Name: References,
Value: string(refs),
})
}
tags := span.GetTags()
for i := range tags {
var value string
switch tags[i].GetVType() {
case model.ValueType_STRING:
value = tags[i].GetVStr()
case model.ValueType_BOOL:
value = strconv.FormatBool(tags[i].GetVBool())
case model.ValueType_INT64:
value = strconv.FormatInt(tags[i].GetVInt64(), 10)
case model.ValueType_FLOAT64:
value = strconv.FormatFloat(tags[i].GetVFloat64(), 'f', -1, 64)
case model.ValueType_BINARY:
value = string(tags[i].GetVBinary())
}
sb.WriteString("tag:")
sb.WriteString(tags[i].GetKey())
var f1 = logstorage.Field{Name: sb.String(), Value: value}
sb.WriteString(":v_type")
var f2 = logstorage.Field{Name: sb.String(), Value: strconv.FormatInt(int64(tags[i].GetVType()), 10)}
sb.Reset()
fields = append(fields, f1, f2)
}
streamFields := make([]logstorage.Field, 0, 2)
streamFields = append(streamFields,
logstorage.Field{Name: ProcessServiceName, Value: span.GetProcess().GetServiceName()},
logstorage.Field{Name: OperationName, Value: span.GetOperationName()},
)
return fields, streamFields, nil
}
func SpanToFields(span *model.Span) ([]logstorage.Field, []logstorage.Field, error) {
fields := make([]logstorage.Field, 0)
fields = append(fields, logstorage.Field{Name: "_msg", Value: "span"},
logstorage.Field{Name: TraceID, Value: span.TraceID.String()},
logstorage.Field{Name: SpanID, Value: span.SpanID.String()},
logstorage.Field{Name: Flags, Value: strconv.FormatUint(uint64(span.Flags), 10)},
logstorage.Field{Name: StartTime, Value: strconv.FormatInt(span.StartTime.UnixNano(), 10)},
logstorage.Field{Name: EndTime, Value: strconv.FormatInt(span.StartTime.Add(span.Duration).UnixNano(), 10)},
logstorage.Field{Name: Duration, Value: strconv.FormatInt(span.Duration.Nanoseconds(), 10)}, logstorage.Field{Name: ProcessID, Value: span.ProcessID},
logstorage.Field{Name: ProcessServiceName, Value: span.GetProcess().GetServiceName()},
logstorage.Field{Name: OperationName, Value: span.GetOperationName()},
)
if tags := span.GetProcess().GetTags(); len(tags) > 0 {
for i := range tags {
var value string
switch tags[i].GetVType() {
case model.ValueType_STRING:
value = tags[i].GetVStr()
case model.ValueType_BOOL:
value = strconv.FormatBool(tags[i].GetVBool())
case model.ValueType_INT64:
value = strconv.FormatInt(tags[i].GetVInt64(), 10)
case model.ValueType_FLOAT64:
value = strconv.FormatFloat(tags[i].GetVFloat64(), 'f', -1, 64)
case model.ValueType_BINARY:
value = string(tags[i].GetVBinary())
}
fields = append(fields, logstorage.Field{
Name: fmt.Sprintf(ProcessTagVType, tags[i].GetKey()),
Value: strconv.FormatInt(int64(tags[i].GetVType()), 10),
}, logstorage.Field{
Name: fmt.Sprintf(ProcessTagKey, tags[i].GetKey()),
Value: value,
})
}
}
if len(span.Logs) > 0 {
logs, err := json.Marshal(span.Logs)
if err != nil {
return nil, nil, err
}
fields = append(fields, logstorage.Field{
Name: Logs,
Value: string(logs),
})
}
if len(span.Warnings) > 0 {
warnings, err := json.Marshal(span.Warnings)
if err != nil {
return nil, nil, err
}
fields = append(fields, logstorage.Field{
Name: Warnings,
Value: string(warnings),
})
}
if len(span.References) > 0 {
refs, err := json.Marshal(span.References)
if err != nil {
return nil, nil, err
}
fields = append(fields, logstorage.Field{
Name: References,
Value: string(refs),
})
}
tags := span.GetTags()
for i := range tags {
var value string
switch tags[i].GetVType() {
case model.ValueType_STRING:
value = tags[i].GetVStr()
case model.ValueType_BOOL:
value = strconv.FormatBool(tags[i].GetVBool())
case model.ValueType_INT64:
value = strconv.FormatInt(tags[i].GetVInt64(), 10)
case model.ValueType_FLOAT64:
value = strconv.FormatFloat(tags[i].GetVFloat64(), 'f', -1, 64)
case model.ValueType_BINARY:
value = string(tags[i].GetVBinary())
}
fields = append(fields, logstorage.Field{
Name: fmt.Sprintf(TagVType, tags[i].GetKey()),
Value: strconv.FormatInt(int64(tags[i].GetVType()), 10),
}, logstorage.Field{
Name: fmt.Sprintf(TagKey, tags[i].GetKey()),
Value: value,
})
}
streamFields := make([]logstorage.Field, 0, 2)
streamFields = append(streamFields,
logstorage.Field{Name: ProcessServiceName, Value: span.GetProcess().GetServiceName()},
logstorage.Field{Name: OperationName, Value: span.GetOperationName()},
)
return fields, streamFields, nil
}
func FieldsToSpan(fields []logstorage.Field) (*model.Span, error) {
sp := &model.Span{
Process: &model.Process{},
}
tagMap, tagVTypeMap, processTagMap, processVTypeMap := make(map[string]string), make(map[string]model.ValueType), make(map[string]string), make(map[string]model.ValueType)
for _, field := range fields {
switch field.Name {
case "_stream":
logstorage.GetStreamTags()
case TraceID:
traceID, err := model.TraceIDFromString(field.Value)
if err != nil {
return nil, err
}
sp.TraceID = traceID
case SpanID:
spanID, err := model.SpanIDFromString(field.Value)
if err != nil {
return nil, err
}
sp.SpanID = spanID
case OperationName:
sp.OperationName = field.Value
case Flags:
flags, err := strconv.ParseUint(field.Value, 10, 32)
if err != nil {
return nil, err
}
sp.Flags = model.Flags(uint32(flags))
case StartTime:
unixNano, err := strconv.ParseInt(field.Value, 10, 64)
if err != nil {
return nil, err
}
sp.StartTime = time.Unix(0, unixNano)
case Duration:
nano, err := strconv.ParseInt(field.Value, 10, 64)
if err != nil {
return nil, err
}
sp.Duration = time.Duration(nano)
case ProcessID:
sp.ProcessID = field.Value
case ProcessServiceName:
sp.Process.ServiceName = field.Value
case Logs:
var logs []model.Log
err := json.Unmarshal([]byte(field.Value), &logs)
if err != nil {
return nil, err
}
sp.Logs = logs
case Warnings:
var warnings []string
err := json.Unmarshal([]byte(field.Value), &warnings)
if err != nil {
return nil, err
}
sp.Warnings = warnings
case References:
var refs []model.SpanRef
err := json.Unmarshal([]byte(field.Value), &refs)
if err != nil {
return nil, err
}
sp.References = refs
default:
if strings.HasPrefix(field.Name, "process_tag:") {
if strings.HasSuffix(field.Name, ":v_type") {
vType, err := strconv.ParseInt(field.Value, 10, 32)
if err != nil {
return nil, err
}
processVTypeMap[strings.TrimSuffix(strings.TrimPrefix(field.Name, "process_tag:"), ":v_type")] = model.ValueType(vType)
} else {
processTagMap[strings.TrimPrefix(field.Name, "process_tag:")] = field.Value
}
} else if strings.HasPrefix(field.Name, "tag:") {
if strings.HasSuffix(field.Name, ":v_type") {
vType, err := strconv.ParseInt(field.Value, 10, 32)
if err != nil {
return nil, err
}
tagVTypeMap[strings.TrimSuffix(strings.TrimPrefix(field.Name, "tag:"), ":v_type")] = model.ValueType(vType)
} else {
tagMap[strings.TrimPrefix(field.Name, "tag:")] = field.Value
}
}
}
}
if len(tagMap) > 0 {
tags, err := mapToTags(tagMap, tagVTypeMap)
if err != nil {
return nil, err
}
sp.Tags = tags
}
if len(processTagMap) > 0 {
tags, err := mapToTags(processTagMap, processVTypeMap)
if err != nil {
return nil, err
}
sp.Process.Tags = tags
}
if sp.SpanID != 0 {
return sp, nil
}
return nil, fmt.Errorf("invalid fields: %v", fields)
}
func mapToTags(tagMap map[string]string, tagVTypeMap map[string]model.ValueType) ([]model.KeyValue, error) {
tags := make([]model.KeyValue, 0, len(tagMap))
for name, vStr := range tagMap {
vType, ok := tagVTypeMap[name]
/*if !ok {
return nil, fmt.Errorf("cannot find tag value type for tag [%s]", name)
} */
if !ok {
// assume tag is of type string
vType = model.ValueType(0)
}
tag := model.KeyValue{
Key: name,
VType: vType,
}
switch vType {
case model.ValueType_STRING:
tag.VStr = vStr
case model.ValueType_BOOL:
v, err := strconv.ParseBool(vStr)
if err != nil {
return nil, err
}
tag.VBool = v
case model.ValueType_INT64:
v, err := strconv.ParseInt(vStr, 10, 64)
if err != nil {
return nil, err
}
tag.VInt64 = v
case model.ValueType_FLOAT64:
v, err := strconv.ParseFloat(vStr, 64)
if err != nil {
return nil, err
}
tag.VFloat64 = v
case model.ValueType_BINARY:
tag.VBinary = []byte(vStr)
}
tags = append(tags, tag)
}
return tags, nil
}

152
lib/jaeger/fields_test.go Normal file
View File

@@ -0,0 +1,152 @@
package jaeger
import (
"strings"
"testing"
"github.com/jaegertracing/jaeger/model"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
)
var span = &model.Span{
TraceID: model.TraceID{Low: 4300929031727684986, High: 12612784095082448122},
SpanID: 0x04210a5512d46c4b,
OperationName: "/",
References: []model.SpanRef{},
Flags: 0,
Duration: 198458,
Tags: []model.KeyValue{
{
Key: "otel.scope.name",
VType: model.StringType,
VStr: "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",
},
{
Key: "otel.scope.version",
VType: model.StringType,
VStr: "0.60.0",
},
{
Key: "httpd.method",
VType: model.StringType,
VStr: "GET",
},
{
Key: "httpd.scheme",
VType: model.StringType,
VStr: "http",
},
{
Key: "net.host.name",
VType: model.StringType,
VStr: "localhost",
},
{
Key: "net.host.port",
VType: model.Int64Type,
VStr: "",
VInt64: 8080,
},
{
Key: "net.sock.peer",
VType: model.StringType,
VStr: "127.0.0.1",
},
{
Key: "net.sock.peer.port",
VType: model.Int64Type,
VStr: "",
VInt64: 59398,
},
{
Key: "user_agent.original",
VType: model.StringType,
VStr: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Safari/605.1.15",
},
{
Key: "http.target",
VType: model.StringType,
VStr: "/",
},
{
Key: "net.protocol.version",
VType: model.StringType,
VStr: "1.1",
},
{
Key: "http.route",
VType: model.StringType,
VStr: "/",
},
{
Key: "http.status_code",
VType: model.Int64Type,
VStr: "",
VInt64: 200,
},
{
Key: "span.kind",
VType: model.StringType,
VStr: "server",
},
},
Logs: nil,
Process: &model.Process{
ServiceName: "frontend",
Tags: []model.KeyValue{
{
Key: "host.name",
VType: model.StringType,
VStr: "orbstack",
},
{
Key: "os.type",
VType: model.StringType,
VStr: "linux",
},
{
Key: "telemetry.sdk.language",
VType: model.StringType,
VStr: "go",
},
{
Key: "telemetry.sdk.name",
VType: model.StringType,
VStr: "opentelemetry",
},
{
Key: "telemetry.sdk.version",
VType: model.StringType,
VStr: "1.35.0",
},
},
},
ProcessID: "",
Warnings: nil,
}
func BenchmarkSpanToFields(b *testing.B) {
for i := 0; i < b.N; i++ {
SpanToFields(span)
}
}
func BenchmarkSpanToFieldsStringBuilder(b *testing.B) {
sb := &strings.Builder{}
sb.Grow(80)
for i := 0; i < b.N; i++ {
SpanToFieldsStringBuilder(sb, span)
}
}
var bbufPool bytesutil.ByteBufferPool
func BenchmarkSpanToFieldsByteBuffer(b *testing.B) {
bbuf := bbufPool.Get()
defer bbufPool.Put(bbuf)
for i := 0; i < b.N; i++ {
SpanToFieldsByteBuffer(bbuf, span)
bbuf.Reset()
}
}

View File

@@ -0,0 +1 @@
Files under `github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/jaeger/proto` are copied from `github.com/jaegertracing/jaeger` with import path modified. For PoC usage only.

59
lib/jaeger/proto/flags.go Normal file
View File

@@ -0,0 +1,59 @@
// Copyright (c) 2019 The Jaeger Authors.
// Copyright (c) 2017 Uber Technologies, Inc.
// SPDX-License-Identifier: Apache-2.0
package proto
const (
// SampledFlag is the bit set in Flags in order to define a span as a sampled span
SampledFlag = Flags(1)
// DebugFlag is the bit set in Flags in order to define a span as a debug span
DebugFlag = Flags(2)
// FirehoseFlag is the bit in Flags in order to define a span as a firehose span
FirehoseFlag = Flags(8)
)
// Flags is a bit map of flags for a span
type Flags uint32
// ------- Flags -------
// SetSampled sets the Flags as sampled
func (f *Flags) SetSampled() {
f.setFlags(SampledFlag)
}
// SetDebug set the Flags as sampled
func (f *Flags) SetDebug() {
f.setFlags(DebugFlag)
}
// SetFirehose set the Flags as firehose enabled
func (f *Flags) SetFirehose() {
f.setFlags(FirehoseFlag)
}
func (f *Flags) setFlags(bit Flags) {
*f |= bit
}
// IsSampled returns true if the Flags denote sampling
func (f Flags) IsSampled() bool {
return f.checkFlags(SampledFlag)
}
// IsDebug returns true if the Flags denote debugging
// Debugging can be useful in testing tracing availability or correctness
func (f Flags) IsDebug() bool {
return f.checkFlags(DebugFlag)
}
// IsFirehoseEnabled returns true if firehose is enabled
// Firehose is used to decide whether to index a span or not
func (f Flags) IsFirehoseEnabled() bool {
return f.checkFlags(FirehoseFlag)
}
func (f Flags) checkFlags(bit Flags) bool {
return f&bit == bit
}

245
lib/jaeger/proto/ids.go Normal file
View File

@@ -0,0 +1,245 @@
// Copyright (c) 2019 The Jaeger Authors.
// Copyright (c) 2018 Uber Technologies, Inc.
// SPDX-License-Identifier: Apache-2.0
package proto
import (
"encoding/base64"
"encoding/binary"
"errors"
"fmt"
"strconv"
"github.com/gogo/protobuf/jsonpb"
)
const (
// traceIDShortBytesLen indicates length of 64bit traceID when represented as list of bytes
traceIDShortBytesLen = 8
// traceIDLongBytesLen indicates length of 128bit traceID when represented as list of bytes
traceIDLongBytesLen = 16
)
// TraceID is a random 128bit identifier for a trace
type TraceID struct {
Low uint64 `json:"lo"`
High uint64 `json:"hi"`
}
// SpanID is a random 64bit identifier for a span
type SpanID uint64
// ------- TraceID -------
// NewTraceID creates a new TraceID from two 64bit unsigned ints.
func NewTraceID(high, low uint64) TraceID {
return TraceID{High: high, Low: low}
}
func (t TraceID) String() string {
if t.High == 0 {
return fmt.Sprintf("%016x", t.Low)
}
return fmt.Sprintf("%016x%016x", t.High, t.Low)
}
// TraceIDFromString creates a TraceID from a hexadecimal string
func TraceIDFromString(s string) (TraceID, error) {
var hi, lo uint64
var err error
switch {
case len(s) > 32:
return TraceID{}, fmt.Errorf("TraceID cannot be longer than 32 hex characters: %s", s)
case len(s) > 16:
hiLen := len(s) - 16
if hi, err = strconv.ParseUint(s[0:hiLen], 16, 64); err != nil {
return TraceID{}, err
}
if lo, err = strconv.ParseUint(s[hiLen:], 16, 64); err != nil {
return TraceID{}, err
}
default:
if lo, err = strconv.ParseUint(s, 16, 64); err != nil {
return TraceID{}, err
}
}
return TraceID{High: hi, Low: lo}, nil
}
// TraceIDFromBytes creates a TraceID from list of bytes
func TraceIDFromBytes(data []byte) (TraceID, error) {
var t TraceID
switch {
case len(data) == traceIDLongBytesLen:
t.High = binary.BigEndian.Uint64(data[:traceIDShortBytesLen])
t.Low = binary.BigEndian.Uint64(data[traceIDShortBytesLen:])
case len(data) == traceIDShortBytesLen:
t.Low = binary.BigEndian.Uint64(data)
default:
return TraceID{}, errors.New("invalid length for TraceID")
}
return t, nil
}
// MarshalText is called by encoding/json, which we do not want people to use.
func (TraceID) MarshalText() ([]byte, error) {
return nil, errors.New("unsupported method TraceID.MarshalText; please use github.com/gogo/protobuf/jsonpb for marshalling")
}
// UnmarshalText is called by encoding/json, which we do not want people to use.
func (*TraceID) UnmarshalText([]byte /* text */) error {
return errors.New("unsupported method TraceID.UnmarshalText; please use github.com/gogo/protobuf/jsonpb for marshalling")
}
// Size returns the size of this datum in protobuf. It is always 16 bytes.
func (*TraceID) Size() int {
return 16
}
// MarshalTo converts trace ID into a binary representation. Called by protobuf serialization.
func (t *TraceID) MarshalTo(data []byte) (n int, err error) {
var b [16]byte
binary.BigEndian.PutUint64(b[:8], uint64(t.High))
binary.BigEndian.PutUint64(b[8:], uint64(t.Low))
return marshalBytes(data, b[:])
}
// Unmarshal inflates this trace ID from binary representation. Called by protobuf serialization.
func (t *TraceID) Unmarshal(data []byte) error {
var err error
*t, err = TraceIDFromBytes(data)
return err
}
func marshalBytes(dst []byte, src []byte) (n int, err error) {
if len(dst) < len(src) {
return 0, errors.New("buffer is too short")
}
return copy(dst, src), nil
}
// MarshalJSON converts trace id into a base64 string enclosed in quotes.
// Used by protobuf JSON serialization.
// Example: {high:2, low:1} => "AAAAAAAAAAIAAAAAAAAAAQ==".
func (t TraceID) MarshalJSON() ([]byte, error) {
var b [16]byte
t.MarshalTo(b[:]) // can only error on incorrect buffer size
s := make([]byte, 24+2)
base64.StdEncoding.Encode(s[1:25], b[:])
s[0], s[25] = '"', '"'
return s, nil
}
// UnmarshalJSON inflates trace id from base64 string, possibly enclosed in quotes.
// Used by protobuf JSON serialization.
func (t *TraceID) UnmarshalJSON(data []byte) error {
s := string(data)
if l := len(s); l > 2 && s[0] == '"' && s[l-1] == '"' {
s = s[1 : l-1]
}
b, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return fmt.Errorf("cannot unmarshal TraceID from string '%s': %w", string(data), err)
}
return t.Unmarshal(b)
}
// ------- SpanID -------
// NewSpanID creates a new SpanID from a 64bit unsigned int.
func NewSpanID(v uint64) SpanID {
return SpanID(v)
}
func (s SpanID) String() string {
return fmt.Sprintf("%016x", uint64(s))
}
// SpanIDFromString creates a SpanID from a hexadecimal string
func SpanIDFromString(s string) (SpanID, error) {
if len(s) > 16 {
return SpanID(0), fmt.Errorf("SpanID cannot be longer than 16 hex characters: %s", s)
}
id, err := strconv.ParseUint(s, 16, 64)
if err != nil {
return SpanID(0), err
}
return SpanID(id), nil
}
// SpanIDFromBytes creates a SpandID from list of bytes
func SpanIDFromBytes(data []byte) (SpanID, error) {
if len(data) != traceIDShortBytesLen {
return SpanID(0), errors.New("invalid length for SpanID")
}
return NewSpanID(binary.BigEndian.Uint64(data)), nil
}
// MarshalText is called by encoding/json, which we do not want people to use.
func (SpanID) MarshalText() ([]byte, error) {
return nil, errors.New("unsupported method SpanID.MarshalText; please use github.com/gogo/protobuf/jsonpb for marshalling")
}
// UnmarshalText is called by encoding/json, which we do not want people to use.
func (*SpanID) UnmarshalText([]byte /* text */) error {
return errors.New("unsupported method SpanID.UnmarshalText; please use github.com/gogo/protobuf/jsonpb for marshalling")
}
// Size returns the size of this datum in protobuf. It is always 8 bytes.
func (*SpanID) Size() int {
return 8
}
// MarshalTo converts span ID into a binary representation. Called by protobuf serialization.
func (s *SpanID) MarshalTo(data []byte) (n int, err error) {
var b [8]byte
binary.BigEndian.PutUint64(b[:], uint64(*s))
return marshalBytes(data, b[:])
}
// Unmarshal inflates span ID from a binary representation. Called by protobuf serialization.
func (s *SpanID) Unmarshal(data []byte) error {
var err error
*s, err = SpanIDFromBytes(data)
return err
}
// MarshalJSON converts span id into a base64 string enclosed in quotes.
// Used by protobuf JSON serialization.
// Example: {1} => "AAAAAAAAAAE=".
func (s SpanID) MarshalJSON() ([]byte, error) {
var b [8]byte
s.MarshalTo(b[:]) // can only error on incorrect buffer size
v := make([]byte, 12+2)
base64.StdEncoding.Encode(v[1:13], b[:])
v[0], v[13] = '"', '"'
return v, nil
}
// UnmarshalJSON inflates span id from base64 string, possibly enclosed in quotes.
// User by protobuf JSON serialization.
//
// There appears to be a bug in gogoproto, as this function is only called for numeric values.
// https://github.com/gogo/protobuf/issues/411#issuecomment-393856837
func (s *SpanID) UnmarshalJSON(data []byte) error {
str := string(data)
if l := len(str); l > 2 && str[0] == '"' && str[l-1] == '"' {
str = str[1 : l-1]
}
b, err := base64.StdEncoding.DecodeString(str)
if err != nil {
return fmt.Errorf("cannot unmarshal SpanID from string '%s': %w", string(data), err)
}
return s.Unmarshal(b)
}
// UnmarshalJSONPB inflates span id from base64 string, possibly enclosed in quotes.
// User by protobuf JSON serialization.
//
// TODO: can be removed once this ticket is fixed:
//
// https://github.com/gogo/protobuf/issues/411#issuecomment-393856837
func (s *SpanID) UnmarshalJSONPB(_ *jsonpb.Unmarshaler, b []byte) error {
return s.UnmarshalJSON(b)
}

3420
lib/jaeger/proto/model.pb.go Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,146 +1,5 @@
# Changelog
## [0.14.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.13.0...auth/v0.14.0) (2025-01-08)
### Features
* **auth:** Add universe domain support to idtoken ([#11059](https://github.com/googleapis/google-cloud-go/issues/11059)) ([72add7e](https://github.com/googleapis/google-cloud-go/commit/72add7e9f8f455af695e8ef79212a4bd3122fb3a))
### Bug Fixes
* **auth/oauth2adapt:** Update golang.org/x/net to v0.33.0 ([e9b0b69](https://github.com/googleapis/google-cloud-go/commit/e9b0b69644ea5b276cacff0a707e8a5e87efafc9))
* **auth:** Fix copy of delegates in impersonate.NewIDTokenCredentials ([#11386](https://github.com/googleapis/google-cloud-go/issues/11386)) ([ff7ef8e](https://github.com/googleapis/google-cloud-go/commit/ff7ef8e7ade7171bce3e4f30ff10a2e9f6c27ca0)), refs [#11379](https://github.com/googleapis/google-cloud-go/issues/11379)
* **auth:** Update golang.org/x/net to v0.33.0 ([e9b0b69](https://github.com/googleapis/google-cloud-go/commit/e9b0b69644ea5b276cacff0a707e8a5e87efafc9))
## [0.13.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.12.1...auth/v0.13.0) (2024-12-13)
### Features
* **auth:** Add logging support ([#11079](https://github.com/googleapis/google-cloud-go/issues/11079)) ([c80e31d](https://github.com/googleapis/google-cloud-go/commit/c80e31df5ecb33a810be3dfb9d9e27ac531aa91d))
* **auth:** Pass logger from auth layer to metadata package ([#11288](https://github.com/googleapis/google-cloud-go/issues/11288)) ([b552efd](https://github.com/googleapis/google-cloud-go/commit/b552efd6ab34e5dfded18438e0fbfd925805614f))
### Bug Fixes
* **auth:** Check compute cred type before non-default flag for DP ([#11255](https://github.com/googleapis/google-cloud-go/issues/11255)) ([4347ca1](https://github.com/googleapis/google-cloud-go/commit/4347ca141892be8ae813399b4b437662a103bc90))
## [0.12.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.12.0...auth/v0.12.1) (2024-12-10)
### Bug Fixes
* **auth:** Correct typo in link ([#11160](https://github.com/googleapis/google-cloud-go/issues/11160)) ([af6fb46](https://github.com/googleapis/google-cloud-go/commit/af6fb46d7cd694ddbe8c9d63bc4cdcd62b9fb2c1))
## [0.12.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.11.0...auth/v0.12.0) (2024-12-04)
### Features
* **auth:** Add support for providing custom certificate URL ([#11006](https://github.com/googleapis/google-cloud-go/issues/11006)) ([ebf3657](https://github.com/googleapis/google-cloud-go/commit/ebf36579724afb375d3974cf1da38f703e3b7dbc)), refs [#11005](https://github.com/googleapis/google-cloud-go/issues/11005)
### Bug Fixes
* **auth:** Ensure endpoints are present in Validator ([#11209](https://github.com/googleapis/google-cloud-go/issues/11209)) ([106cd53](https://github.com/googleapis/google-cloud-go/commit/106cd53309facaef1b8ea78376179f523f6912b9)), refs [#11006](https://github.com/googleapis/google-cloud-go/issues/11006) [#11190](https://github.com/googleapis/google-cloud-go/issues/11190) [#11189](https://github.com/googleapis/google-cloud-go/issues/11189) [#11188](https://github.com/googleapis/google-cloud-go/issues/11188)
## [0.11.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.10.2...auth/v0.11.0) (2024-11-21)
### Features
* **auth:** Add universe domain support to mTLS ([#11159](https://github.com/googleapis/google-cloud-go/issues/11159)) ([117748b](https://github.com/googleapis/google-cloud-go/commit/117748ba1cfd4ae62a6a4feb7e30951cb2bc9344))
## [0.10.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.10.1...auth/v0.10.2) (2024-11-12)
### Bug Fixes
* **auth:** Restore use of grpc.Dial ([#11118](https://github.com/googleapis/google-cloud-go/issues/11118)) ([2456b94](https://github.com/googleapis/google-cloud-go/commit/2456b943b7b8aaabd4d8bfb7572c0f477ae0db45)), refs [#7556](https://github.com/googleapis/google-cloud-go/issues/7556)
## [0.10.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.10.0...auth/v0.10.1) (2024-11-06)
### Bug Fixes
* **auth:** Restore Application Default Credentials support to idtoken ([#11083](https://github.com/googleapis/google-cloud-go/issues/11083)) ([8771f2e](https://github.com/googleapis/google-cloud-go/commit/8771f2ea9807ab822083808e0678392edff3b4f2))
* **auth:** Skip impersonate universe domain check if empty ([#11086](https://github.com/googleapis/google-cloud-go/issues/11086)) ([87159c1](https://github.com/googleapis/google-cloud-go/commit/87159c1059d4a18d1367ce62746a838a94964ab6))
## [0.10.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.9...auth/v0.10.0) (2024-10-30)
### Features
* **auth:** Add universe domain support to credentials/impersonate ([#10953](https://github.com/googleapis/google-cloud-go/issues/10953)) ([e06cb64](https://github.com/googleapis/google-cloud-go/commit/e06cb6499f7eda3aef08ab18ff197016f667684b))
## [0.9.9](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.8...auth/v0.9.9) (2024-10-22)
### Bug Fixes
* **auth:** Fallback cert lookups for missing files ([#11013](https://github.com/googleapis/google-cloud-go/issues/11013)) ([bd76695](https://github.com/googleapis/google-cloud-go/commit/bd766957ec238b7c40ddbabb369e612dc9b07313)), refs [#10844](https://github.com/googleapis/google-cloud-go/issues/10844)
* **auth:** Replace MDS endpoint universe_domain with universe-domain ([#11000](https://github.com/googleapis/google-cloud-go/issues/11000)) ([6a1586f](https://github.com/googleapis/google-cloud-go/commit/6a1586f2ce9974684affaea84e7b629313b4d114))
## [0.9.8](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.7...auth/v0.9.8) (2024-10-09)
### Bug Fixes
* **auth:** Restore OpenTelemetry handling in transports ([#10968](https://github.com/googleapis/google-cloud-go/issues/10968)) ([08c6d04](https://github.com/googleapis/google-cloud-go/commit/08c6d04901c1a20e219b2d86df41dbaa6d7d7b55)), refs [#10962](https://github.com/googleapis/google-cloud-go/issues/10962)
* **auth:** Try talk to plaintext S2A if credentials can not be found for mTLS-S2A ([#10941](https://github.com/googleapis/google-cloud-go/issues/10941)) ([0f0bf2d](https://github.com/googleapis/google-cloud-go/commit/0f0bf2d18c97dd8b65bcf0099f0802b5631c6287))
## [0.9.7](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.6...auth/v0.9.7) (2024-10-01)
### Bug Fixes
* **auth:** Restore support for non-default service accounts for DirectPath ([#10937](https://github.com/googleapis/google-cloud-go/issues/10937)) ([a38650e](https://github.com/googleapis/google-cloud-go/commit/a38650edbf420223077498cafa537aec74b37aad)), refs [#10907](https://github.com/googleapis/google-cloud-go/issues/10907)
## [0.9.6](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.5...auth/v0.9.6) (2024-09-30)
### Bug Fixes
* **auth:** Make aws credentials provider retrieve fresh credentials ([#10920](https://github.com/googleapis/google-cloud-go/issues/10920)) ([250fbf8](https://github.com/googleapis/google-cloud-go/commit/250fbf87d858d865e399a241b7e537c4ff0c3dd8))
## [0.9.5](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.4...auth/v0.9.5) (2024-09-25)
### Bug Fixes
* **auth:** Restore support for GOOGLE_CLOUD_UNIVERSE_DOMAIN env ([#10915](https://github.com/googleapis/google-cloud-go/issues/10915)) ([94caaaa](https://github.com/googleapis/google-cloud-go/commit/94caaaa061362d0e00ef6214afcc8a0a3e7ebfb2))
* **auth:** Skip directpath credentials overwrite when it's not on GCE ([#10833](https://github.com/googleapis/google-cloud-go/issues/10833)) ([7e5e8d1](https://github.com/googleapis/google-cloud-go/commit/7e5e8d10b761b0a6e43e19a028528db361bc07b1))
* **auth:** Use new context for non-blocking token refresh ([#10919](https://github.com/googleapis/google-cloud-go/issues/10919)) ([cf7102d](https://github.com/googleapis/google-cloud-go/commit/cf7102d33a21be1e5a9d47a49456b3a57c43b350))
## [0.9.4](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.3...auth/v0.9.4) (2024-09-11)
### Bug Fixes
* **auth:** Enable self-signed JWT for non-GDU universe domain ([#10831](https://github.com/googleapis/google-cloud-go/issues/10831)) ([f9869f7](https://github.com/googleapis/google-cloud-go/commit/f9869f7903cfd34d1b97c25d0dc5669d2c5138e6))
## [0.9.3](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.2...auth/v0.9.3) (2024-09-03)
### Bug Fixes
* **auth:** Choose quota project envvar over file when both present ([#10807](https://github.com/googleapis/google-cloud-go/issues/10807)) ([2d8dd77](https://github.com/googleapis/google-cloud-go/commit/2d8dd7700eff92d4b95027be55e26e1e7aa79181)), refs [#10804](https://github.com/googleapis/google-cloud-go/issues/10804)
## [0.9.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.1...auth/v0.9.2) (2024-08-30)
### Bug Fixes
* **auth:** Handle non-Transport DefaultTransport ([#10733](https://github.com/googleapis/google-cloud-go/issues/10733)) ([98d91dc](https://github.com/googleapis/google-cloud-go/commit/98d91dc8316b247498fab41ab35e57a0446fe556)), refs [#10742](https://github.com/googleapis/google-cloud-go/issues/10742)
* **auth:** Make sure quota option takes precedence over env/file ([#10797](https://github.com/googleapis/google-cloud-go/issues/10797)) ([f1b050d](https://github.com/googleapis/google-cloud-go/commit/f1b050d56d804b245cab048c2980d32b0eaceb4e)), refs [#10795](https://github.com/googleapis/google-cloud-go/issues/10795)
### Documentation
* **auth:** Fix Go doc comment link ([#10751](https://github.com/googleapis/google-cloud-go/issues/10751)) ([015acfa](https://github.com/googleapis/google-cloud-go/commit/015acfab4d172650928bb1119bc2cd6307b9a437))
## [0.9.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.0...auth/v0.9.1) (2024-08-22)

View File

@@ -1,40 +1,4 @@
# Google Auth Library for Go
# auth
[![Go Reference](https://pkg.go.dev/badge/cloud.google.com/go/auth.svg)](https://pkg.go.dev/cloud.google.com/go/auth)
## Install
``` bash
go get cloud.google.com/go/auth@latest
```
## Usage
The most common way this library is used is transitively, by default, from any
of our Go client libraries.
### Notable use-cases
- To create a credential directly please see examples in the
[credentials](https://pkg.go.dev/cloud.google.com/go/auth/credentials)
package.
- To create a authenticated HTTP client please see examples in the
[httptransport](https://pkg.go.dev/cloud.google.com/go/auth/httptransport)
package.
- To create a authenticated gRPC connection please see examples in the
[grpctransport](https://pkg.go.dev/cloud.google.com/go/auth/grpctransport)
package.
- To create an ID token please see examples in the
[idtoken](https://pkg.go.dev/cloud.google.com/go/auth/credentials/idtoken)
package.
## Contributing
Contributions are welcome. Please, see the
[CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md)
document for details.
Please note that this project is released with a Contributor Code of Conduct.
By participating in this project you agree to abide by its terms.
See [Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md#contributor-code-of-conduct)
for more information.
This module is currently EXPERIMENTAL and under active development. It is not
yet intended to be used.

View File

@@ -12,11 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package auth provides utilities for managing Google Cloud credentials,
// including functionality for creating, caching, and refreshing OAuth2 tokens.
// It offers customizable options for different OAuth2 flows, such as 2-legged
// (2LO) and 3-legged (3LO) OAuth, along with support for PKCE and automatic
// token management.
package auth
import (
@@ -24,7 +19,6 @@ import (
"encoding/json"
"errors"
"fmt"
"log/slog"
"net/http"
"net/url"
"strings"
@@ -33,7 +27,6 @@ import (
"cloud.google.com/go/auth/internal"
"cloud.google.com/go/auth/internal/jwt"
"github.com/googleapis/gax-go/v2/internallog"
)
const (
@@ -137,9 +130,7 @@ func (t *Token) isEmpty() bool {
}
// Credentials holds Google credentials, including
// [Application Default Credentials].
//
// [Application Default Credentials]: https://developers.google.com/accounts/docs/application-default-credentials
// [Application Default Credentials](https://developers.google.com/accounts/docs/application-default-credentials).
type Credentials struct {
json []byte
projectID CredentialsPropertyProvider
@@ -229,7 +220,9 @@ type CredentialsOptions struct {
UniverseDomainProvider CredentialsPropertyProvider
}
// NewCredentials returns new [Credentials] from the provided options.
// NewCredentials returns new [Credentials] from the provided options. Most users
// will want to build this object a function from the
// [cloud.google.com/go/auth/credentials] package.
func NewCredentials(opts *CredentialsOptions) *Credentials {
creds := &Credentials{
TokenProvider: opts.TokenProvider,
@@ -242,8 +235,8 @@ func NewCredentials(opts *CredentialsOptions) *Credentials {
return creds
}
// CachedTokenProviderOptions provides options for configuring a cached
// [TokenProvider].
// CachedTokenProviderOptions provided options for configuring a
// CachedTokenProvider.
type CachedTokenProviderOptions struct {
// DisableAutoRefresh makes the TokenProvider always return the same token,
// even if it is expired. The default is false. Optional.
@@ -253,7 +246,7 @@ type CachedTokenProviderOptions struct {
// seconds. Optional.
ExpireEarly time.Duration
// DisableAsyncRefresh configures a synchronous workflow that refreshes
// tokens in a blocking manner. The default is false. Optional.
// stale tokens while blocking. The default is false. Optional.
DisableAsyncRefresh bool
}
@@ -280,7 +273,12 @@ func (ctpo *CachedTokenProviderOptions) blockingRefresh() bool {
// NewCachedTokenProvider wraps a [TokenProvider] to cache the tokens returned
// by the underlying provider. By default it will refresh tokens asynchronously
// a few minutes before they expire.
// (non-blocking mode) within a window that starts 3 minutes and 45 seconds
// before they expire. The asynchronous (non-blocking) refresh can be changed to
// a synchronous (blocking) refresh using the
// CachedTokenProviderOptions.DisableAsyncRefresh option. The time-before-expiry
// duration can be configured using the CachedTokenProviderOptions.ExpireEarly
// option.
func NewCachedTokenProvider(tp TokenProvider, opts *CachedTokenProviderOptions) TokenProvider {
if ctp, ok := tp.(*cachedTokenProvider); ok {
return ctp
@@ -323,9 +321,7 @@ func (c *cachedTokenProvider) tokenNonBlocking(ctx context.Context) (*Token, err
defer c.mu.Unlock()
return c.cachedToken, nil
case stale:
// Call tokenAsync with a new Context because the user-provided context
// may have a short timeout incompatible with async token refresh.
c.tokenAsync(context.Background())
c.tokenAsync(ctx)
// Return the stale token immediately to not block customer requests to Cloud services.
c.mu.Lock()
defer c.mu.Unlock()
@@ -340,14 +336,13 @@ func (c *cachedTokenProvider) tokenState() tokenState {
c.mu.Lock()
defer c.mu.Unlock()
t := c.cachedToken
now := timeNow()
if t == nil || t.Value == "" {
return invalid
} else if t.Expiry.IsZero() {
return fresh
} else if now.After(t.Expiry.Round(0)) {
} else if timeNow().After(t.Expiry.Round(0)) {
return invalid
} else if now.After(t.Expiry.Round(0).Add(-c.expireEarly)) {
} else if timeNow().After(t.Expiry.Round(0).Add(-c.expireEarly)) {
return stale
}
return fresh
@@ -492,11 +487,6 @@ type Options2LO struct {
// UseIDToken requests that the token returned be an ID token if one is
// returned from the server. Optional.
UseIDToken bool
// Logger is used for debug logging. If provided, logging will be enabled
// at the loggers configured level. By default logging is disabled unless
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
// logger will be used. Optional.
Logger *slog.Logger
}
func (o *Options2LO) client() *http.Client {
@@ -527,13 +517,12 @@ func New2LOTokenProvider(opts *Options2LO) (TokenProvider, error) {
if err := opts.validate(); err != nil {
return nil, err
}
return tokenProvider2LO{opts: opts, Client: opts.client(), logger: internallog.New(opts.Logger)}, nil
return tokenProvider2LO{opts: opts, Client: opts.client()}, nil
}
type tokenProvider2LO struct {
opts *Options2LO
Client *http.Client
logger *slog.Logger
}
func (tp tokenProvider2LO) Token(ctx context.Context) (*Token, error) {
@@ -568,12 +557,10 @@ func (tp tokenProvider2LO) Token(ctx context.Context) (*Token, error) {
return nil, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
tp.logger.DebugContext(ctx, "2LO token request", "request", internallog.HTTPRequest(req, []byte(v.Encode())))
resp, body, err := internal.DoRequest(tp.Client, req)
if err != nil {
return nil, fmt.Errorf("auth: cannot fetch token: %w", err)
}
tp.logger.DebugContext(ctx, "2LO token response", "response", internallog.HTTPResponse(resp, body))
if c := resp.StatusCode; c < http.StatusOK || c >= http.StatusMultipleChoices {
return nil, &Error{
Response: resp,

View File

@@ -37,11 +37,8 @@ var (
// computeTokenProvider creates a [cloud.google.com/go/auth.TokenProvider] that
// uses the metadata service to retrieve tokens.
func computeTokenProvider(opts *DetectOptions, client *metadata.Client) auth.TokenProvider {
return auth.NewCachedTokenProvider(&computeProvider{
scopes: opts.Scopes,
client: client,
}, &auth.CachedTokenProviderOptions{
func computeTokenProvider(opts *DetectOptions) auth.TokenProvider {
return auth.NewCachedTokenProvider(computeProvider{scopes: opts.Scopes}, &auth.CachedTokenProviderOptions{
ExpireEarly: opts.EarlyTokenRefresh,
DisableAsyncRefresh: opts.DisableAsyncRefresh,
})
@@ -50,7 +47,6 @@ func computeTokenProvider(opts *DetectOptions, client *metadata.Client) auth.Tok
// computeProvider fetches tokens from the google cloud metadata service.
type computeProvider struct {
scopes []string
client *metadata.Client
}
type metadataTokenResp struct {
@@ -59,7 +55,7 @@ type metadataTokenResp struct {
TokenType string `json:"token_type"`
}
func (cs *computeProvider) Token(ctx context.Context) (*auth.Token, error) {
func (cs computeProvider) Token(ctx context.Context) (*auth.Token, error) {
tokenURI, err := url.Parse(computeTokenURI)
if err != nil {
return nil, err
@@ -69,7 +65,7 @@ func (cs *computeProvider) Token(ctx context.Context) (*auth.Token, error) {
v.Set("scopes", strings.Join(cs.scopes, ","))
tokenURI.RawQuery = v.Encode()
}
tokenJSON, err := cs.client.GetWithContext(ctx, tokenURI.String())
tokenJSON, err := metadata.GetWithContext(ctx, tokenURI.String())
if err != nil {
return nil, fmt.Errorf("credentials: cannot fetch token: %w", err)
}

View File

@@ -19,7 +19,6 @@ import (
"encoding/json"
"errors"
"fmt"
"log/slog"
"net/http"
"os"
"time"
@@ -28,7 +27,6 @@ import (
"cloud.google.com/go/auth/internal"
"cloud.google.com/go/auth/internal/credsfile"
"cloud.google.com/go/compute/metadata"
"github.com/googleapis/gax-go/v2/internallog"
)
const (
@@ -98,17 +96,12 @@ func DetectDefault(opts *DetectOptions) (*auth.Credentials, error) {
}
if OnGCE() {
metadataClient := metadata.NewWithOptions(&metadata.Options{
Logger: opts.logger(),
})
return auth.NewCredentials(&auth.CredentialsOptions{
TokenProvider: computeTokenProvider(opts, metadataClient),
ProjectIDProvider: auth.CredentialsPropertyFunc(func(ctx context.Context) (string, error) {
return metadataClient.ProjectIDWithContext(ctx)
TokenProvider: computeTokenProvider(opts),
ProjectIDProvider: auth.CredentialsPropertyFunc(func(context.Context) (string, error) {
return metadata.ProjectID()
}),
UniverseDomainProvider: &internal.ComputeUniverseDomainProvider{
MetadataClient: metadataClient,
},
UniverseDomainProvider: &internal.ComputeUniverseDomainProvider{},
}), nil
}
@@ -165,11 +158,6 @@ type DetectOptions struct {
// The default value is "googleapis.com". This option is ignored for
// authentication flows that do not support universe domain. Optional.
UniverseDomain string
// Logger is used for debug logging. If provided, logging will be enabled
// at the loggers configured level. By default logging is disabled unless
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
// logger will be used. Optional.
Logger *slog.Logger
}
func (o *DetectOptions) validate() error {
@@ -205,10 +193,6 @@ func (o *DetectOptions) client() *http.Client {
return internal.DefaultClient()
}
func (o *DetectOptions) logger() *slog.Logger {
return internallog.New(o.Logger)
}
func readCredentialsFile(filename string, opts *DetectOptions) (*auth.Credentials, error) {
b, err := os.ReadFile(filename)
if err != nil {
@@ -269,7 +253,6 @@ func clientCredConfigFromJSON(b []byte, opts *DetectOptions) *auth.Options3LO {
AuthURL: c.AuthURI,
TokenURL: c.TokenURI,
Client: opts.client(),
Logger: opts.logger(),
EarlyTokenExpiry: opts.EarlyTokenRefresh,
AuthHandlerOpts: handleOpts,
// TODO(codyoss): refactor this out. We need to add in auto-detection

View File

@@ -33,7 +33,7 @@ func fileCredentials(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
return nil, err
}
var projectID, universeDomain string
var projectID, quotaProjectID, universeDomain string
var tp auth.TokenProvider
switch fileType {
case credsfile.ServiceAccountKey:
@@ -56,6 +56,7 @@ func fileCredentials(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
if err != nil {
return nil, err
}
quotaProjectID = f.QuotaProjectID
universeDomain = f.UniverseDomain
case credsfile.ExternalAccountKey:
f, err := credsfile.ParseExternalAccount(b)
@@ -66,6 +67,7 @@ func fileCredentials(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
if err != nil {
return nil, err
}
quotaProjectID = f.QuotaProjectID
universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
case credsfile.ExternalAccountAuthorizedUserKey:
f, err := credsfile.ParseExternalAccountAuthorizedUser(b)
@@ -76,6 +78,7 @@ func fileCredentials(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
if err != nil {
return nil, err
}
quotaProjectID = f.QuotaProjectID
universeDomain = f.UniverseDomain
case credsfile.ImpersonatedServiceAccountKey:
f, err := credsfile.ParseImpersonatedServiceAccount(b)
@@ -105,9 +108,9 @@ func fileCredentials(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
TokenProvider: auth.NewCachedTokenProvider(tp, &auth.CachedTokenProviderOptions{
ExpireEarly: opts.EarlyTokenRefresh,
}),
JSON: b,
ProjectIDProvider: internalauth.StaticCredentialsProperty(projectID),
// TODO(codyoss): only set quota project here if there was a user override
JSON: b,
ProjectIDProvider: internalauth.StaticCredentialsProperty(projectID),
QuotaProjectIDProvider: internalauth.StaticCredentialsProperty(quotaProjectID),
UniverseDomainProvider: internalauth.StaticCredentialsProperty(universeDomain),
}), nil
}
@@ -124,14 +127,8 @@ func resolveUniverseDomain(optsUniverseDomain, fileUniverseDomain string) string
}
func handleServiceAccount(f *credsfile.ServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
ud := resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
if opts.UseSelfSignedJWT {
return configureSelfSignedJWT(f, opts)
} else if ud != "" && ud != internalauth.DefaultUniverseDomain {
// For non-GDU universe domains, token exchange is impossible and services
// must support self-signed JWTs.
opts.UseSelfSignedJWT = true
return configureSelfSignedJWT(f, opts)
}
opts2LO := &auth.Options2LO{
Email: f.ClientEmail,
@@ -141,7 +138,6 @@ func handleServiceAccount(f *credsfile.ServiceAccountFile, opts *DetectOptions)
TokenURL: f.TokenURL,
Subject: opts.Subject,
Client: opts.client(),
Logger: opts.logger(),
}
if opts2LO.TokenURL == "" {
opts2LO.TokenURL = jwtTokenURL
@@ -160,7 +156,6 @@ func handleUserCredential(f *credsfile.UserCredentialsFile, opts *DetectOptions)
EarlyTokenExpiry: opts.EarlyTokenRefresh,
RefreshToken: f.RefreshToken,
Client: opts.client(),
Logger: opts.logger(),
}
return auth.New3LOTokenProvider(opts3LO)
}
@@ -179,7 +174,6 @@ func handleExternalAccount(f *credsfile.ExternalAccountFile, opts *DetectOptions
Scopes: opts.scopes(),
WorkforcePoolUserProject: f.WorkforcePoolUserProject,
Client: opts.client(),
Logger: opts.logger(),
IsDefaultClient: opts.Client == nil,
}
if f.ServiceAccountImpersonation != nil {
@@ -198,7 +192,6 @@ func handleExternalAccountAuthorizedUser(f *credsfile.ExternalAccountAuthorizedU
ClientSecret: f.ClientSecret,
Scopes: opts.scopes(),
Client: opts.client(),
Logger: opts.logger(),
}
return externalaccountuser.NewTokenProvider(externalOpts)
}
@@ -218,7 +211,6 @@ func handleImpersonatedServiceAccount(f *credsfile.ImpersonatedServiceAccountFil
Tp: tp,
Delegates: f.Delegates,
Client: opts.client(),
Logger: opts.logger(),
})
}
@@ -226,6 +218,5 @@ func handleGDCHServiceAccount(f *credsfile.GDCHServiceAccountFile, opts *DetectO
return gdch.NewTokenProvider(f, &gdch.Options{
STSAudience: opts.STSAudience,
Client: opts.client(),
Logger: opts.logger(),
})
}

View File

@@ -23,7 +23,6 @@ import (
"encoding/json"
"errors"
"fmt"
"log/slog"
"net/http"
"net/url"
"os"
@@ -33,7 +32,6 @@ import (
"time"
"cloud.google.com/go/auth/internal"
"github.com/googleapis/gax-go/v2/internallog"
)
var (
@@ -89,7 +87,6 @@ type awsSubjectProvider struct {
reqOpts *RequestOptions
Client *http.Client
logger *slog.Logger
}
func (sp *awsSubjectProvider) subjectToken(ctx context.Context) (string, error) {
@@ -97,28 +94,30 @@ func (sp *awsSubjectProvider) subjectToken(ctx context.Context) (string, error)
if sp.RegionalCredVerificationURL == "" {
sp.RegionalCredVerificationURL = defaultRegionalCredentialVerificationURL
}
headers := make(map[string]string)
if sp.shouldUseMetadataServer() {
awsSessionToken, err := sp.getAWSSessionToken(ctx)
if sp.requestSigner == nil {
headers := make(map[string]string)
if sp.shouldUseMetadataServer() {
awsSessionToken, err := sp.getAWSSessionToken(ctx)
if err != nil {
return "", err
}
if awsSessionToken != "" {
headers[awsIMDSv2SessionTokenHeader] = awsSessionToken
}
}
awsSecurityCredentials, err := sp.getSecurityCredentials(ctx, headers)
if err != nil {
return "", err
}
if awsSessionToken != "" {
headers[awsIMDSv2SessionTokenHeader] = awsSessionToken
if sp.region, err = sp.getRegion(ctx, headers); err != nil {
return "", err
}
sp.requestSigner = &awsRequestSigner{
RegionName: sp.region,
AwsSecurityCredentials: awsSecurityCredentials,
}
}
awsSecurityCredentials, err := sp.getSecurityCredentials(ctx, headers)
if err != nil {
return "", err
}
if sp.region, err = sp.getRegion(ctx, headers); err != nil {
return "", err
}
sp.requestSigner = &awsRequestSigner{
RegionName: sp.region,
AwsSecurityCredentials: awsSecurityCredentials,
}
// Generate the signed request to AWS STS GetCallerIdentity API.
@@ -195,12 +194,10 @@ func (sp *awsSubjectProvider) getAWSSessionToken(ctx context.Context) (string, e
}
req.Header.Set(awsIMDSv2SessionTTLHeader, awsIMDSv2SessionTTL)
sp.logger.DebugContext(ctx, "aws session token request", "request", internallog.HTTPRequest(req, nil))
resp, body, err := internal.DoRequest(sp.Client, req)
if err != nil {
return "", err
}
sp.logger.DebugContext(ctx, "aws session token response", "response", internallog.HTTPResponse(resp, body))
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("credentials: unable to retrieve AWS session token: %s", body)
}
@@ -230,12 +227,10 @@ func (sp *awsSubjectProvider) getRegion(ctx context.Context, headers map[string]
for name, value := range headers {
req.Header.Add(name, value)
}
sp.logger.DebugContext(ctx, "aws region request", "request", internallog.HTTPRequest(req, nil))
resp, body, err := internal.DoRequest(sp.Client, req)
if err != nil {
return "", err
}
sp.logger.DebugContext(ctx, "aws region response", "response", internallog.HTTPResponse(resp, body))
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("credentials: unable to retrieve AWS region - %s", body)
}
@@ -290,12 +285,10 @@ func (sp *awsSubjectProvider) getMetadataSecurityCredentials(ctx context.Context
for name, value := range headers {
req.Header.Add(name, value)
}
sp.logger.DebugContext(ctx, "aws security credential request", "request", internallog.HTTPRequest(req, nil))
resp, body, err := internal.DoRequest(sp.Client, req)
if err != nil {
return result, err
}
sp.logger.DebugContext(ctx, "aws security credential response", "response", internallog.HTTPResponse(resp, body))
if resp.StatusCode != http.StatusOK {
return result, fmt.Errorf("credentials: unable to retrieve AWS security credentials - %s", body)
}
@@ -317,12 +310,10 @@ func (sp *awsSubjectProvider) getMetadataRoleName(ctx context.Context, headers m
req.Header.Add(name, value)
}
sp.logger.DebugContext(ctx, "aws metadata role request", "request", internallog.HTTPRequest(req, nil))
resp, body, err := internal.DoRequest(sp.Client, req)
if err != nil {
return "", err
}
sp.logger.DebugContext(ctx, "aws metadata role response", "response", internallog.HTTPResponse(resp, body))
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("credentials: unable to retrieve AWS role name - %s", body)
}

View File

@@ -18,7 +18,6 @@ import (
"context"
"errors"
"fmt"
"log/slog"
"net/http"
"regexp"
"strconv"
@@ -29,7 +28,6 @@ import (
"cloud.google.com/go/auth/credentials/internal/impersonate"
"cloud.google.com/go/auth/credentials/internal/stsexchange"
"cloud.google.com/go/auth/internal/credsfile"
"github.com/googleapis/gax-go/v2/internallog"
)
const (
@@ -106,11 +104,6 @@ type Options struct {
// This is important for X509 credentials which should create a new client if the default was used
// but should respect a client explicitly passed in by the user.
IsDefaultClient bool
// Logger is used for debug logging. If provided, logging will be enabled
// at the loggers configured level. By default logging is disabled unless
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
// logger will be used. Optional.
Logger *slog.Logger
}
// SubjectTokenProvider can be used to supply a subject token to exchange for a
@@ -231,7 +224,6 @@ func NewTokenProvider(opts *Options) (auth.TokenProvider, error) {
return nil, err
}
opts.resolveTokenURL()
logger := internallog.New(opts.Logger)
stp, err := newSubjectTokenProvider(opts)
if err != nil {
return nil, err
@@ -246,7 +238,6 @@ func NewTokenProvider(opts *Options) (auth.TokenProvider, error) {
client: client,
opts: opts,
stp: stp,
logger: logger,
}
if opts.ServiceAccountImpersonationURL == "" {
@@ -263,7 +254,6 @@ func NewTokenProvider(opts *Options) (auth.TokenProvider, error) {
Scopes: scopes,
Tp: auth.NewCachedTokenProvider(tp, nil),
TokenLifetimeSeconds: opts.ServiceAccountImpersonationLifetimeSeconds,
Logger: logger,
})
if err != nil {
return nil, err
@@ -279,7 +269,6 @@ type subjectTokenProvider interface {
// tokenProvider is the provider that handles external credentials. It is used to retrieve Tokens.
type tokenProvider struct {
client *http.Client
logger *slog.Logger
opts *Options
stp subjectTokenProvider
}
@@ -321,7 +310,6 @@ func (tp *tokenProvider) Token(ctx context.Context) (*auth.Token, error) {
Authentication: clientAuth,
Headers: header,
ExtraOpts: options,
Logger: tp.logger,
})
if err != nil {
return nil, err
@@ -342,14 +330,12 @@ func (tp *tokenProvider) Token(ctx context.Context) (*auth.Token, error) {
// newSubjectTokenProvider determines the type of credsfile.CredentialSource needed to create a
// subjectTokenProvider
func newSubjectTokenProvider(o *Options) (subjectTokenProvider, error) {
logger := internallog.New(o.Logger)
reqOpts := &RequestOptions{Audience: o.Audience, SubjectTokenType: o.SubjectTokenType}
if o.AwsSecurityCredentialsProvider != nil {
return &awsSubjectProvider{
securityCredentialsProvider: o.AwsSecurityCredentialsProvider,
TargetResource: o.Audience,
reqOpts: reqOpts,
logger: logger,
}, nil
} else if o.SubjectTokenProvider != nil {
return &programmaticProvider{stp: o.SubjectTokenProvider, opts: reqOpts}, nil
@@ -366,7 +352,6 @@ func newSubjectTokenProvider(o *Options) (subjectTokenProvider, error) {
CredVerificationURL: o.CredentialSource.URL,
TargetResource: o.Audience,
Client: o.Client,
logger: logger,
}
if o.CredentialSource.IMDSv2SessionTokenURL != "" {
awsProvider.IMDSv2SessionTokenURL = o.CredentialSource.IMDSv2SessionTokenURL
@@ -377,13 +362,7 @@ func newSubjectTokenProvider(o *Options) (subjectTokenProvider, error) {
} else if o.CredentialSource.File != "" {
return &fileSubjectProvider{File: o.CredentialSource.File, Format: o.CredentialSource.Format}, nil
} else if o.CredentialSource.URL != "" {
return &urlSubjectProvider{
URL: o.CredentialSource.URL,
Headers: o.CredentialSource.Headers,
Format: o.CredentialSource.Format,
Client: o.Client,
Logger: logger,
}, nil
return &urlSubjectProvider{URL: o.CredentialSource.URL, Headers: o.CredentialSource.Headers, Format: o.CredentialSource.Format, Client: o.Client}, nil
} else if o.CredentialSource.Executable != nil {
ec := o.CredentialSource.Executable
if ec.Command == "" {

View File

@@ -19,12 +19,10 @@ import (
"encoding/json"
"errors"
"fmt"
"log/slog"
"net/http"
"cloud.google.com/go/auth/internal"
"cloud.google.com/go/auth/internal/credsfile"
"github.com/googleapis/gax-go/v2/internallog"
)
const (
@@ -40,7 +38,6 @@ type urlSubjectProvider struct {
Headers map[string]string
Format *credsfile.Format
Client *http.Client
Logger *slog.Logger
}
func (sp *urlSubjectProvider) subjectToken(ctx context.Context) (string, error) {
@@ -52,12 +49,10 @@ func (sp *urlSubjectProvider) subjectToken(ctx context.Context) (string, error)
for key, val := range sp.Headers {
req.Header.Add(key, val)
}
sp.Logger.DebugContext(ctx, "url subject token request", "request", internallog.HTTPRequest(req, nil))
resp, body, err := internal.DoRequest(sp.Client, req)
if err != nil {
return "", fmt.Errorf("credentials: invalid response when retrieving subject token: %w", err)
}
sp.Logger.DebugContext(ctx, "url subject token response", "response", internallog.HTTPResponse(resp, body))
if c := resp.StatusCode; c < http.StatusOK || c >= http.StatusMultipleChoices {
return "", fmt.Errorf("credentials: status code %d: %s", c, body)
}

View File

@@ -17,14 +17,12 @@ package externalaccountuser
import (
"context"
"errors"
"log/slog"
"net/http"
"time"
"cloud.google.com/go/auth"
"cloud.google.com/go/auth/credentials/internal/stsexchange"
"cloud.google.com/go/auth/internal"
"github.com/googleapis/gax-go/v2/internallog"
)
// Options stores the configuration for fetching tokens with external authorized
@@ -53,8 +51,6 @@ type Options struct {
// Client for token request.
Client *http.Client
// Logger for logging.
Logger *slog.Logger
}
func (c *Options) validate() bool {
@@ -94,7 +90,6 @@ func (tp *tokenProvider) Token(ctx context.Context) (*auth.Token, error) {
RefreshToken: opts.RefreshToken,
Authentication: clientAuth,
Headers: headers,
Logger: internallog.New(tp.o.Logger),
})
if err != nil {
return nil, err

View File

@@ -16,13 +16,12 @@ package gdch
import (
"context"
"crypto"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"encoding/json"
"errors"
"fmt"
"log/slog"
"net/http"
"net/url"
"os"
@@ -33,7 +32,6 @@ import (
"cloud.google.com/go/auth/internal"
"cloud.google.com/go/auth/internal/credsfile"
"cloud.google.com/go/auth/internal/jwt"
"github.com/googleapis/gax-go/v2/internallog"
)
const (
@@ -53,7 +51,6 @@ var (
type Options struct {
STSAudience string
Client *http.Client
Logger *slog.Logger
}
// NewTokenProvider returns a [cloud.google.com/go/auth.TokenProvider] from a
@@ -65,7 +62,7 @@ func NewTokenProvider(f *credsfile.GDCHServiceAccountFile, o *Options) (auth.Tok
if o.STSAudience == "" {
return nil, errors.New("credentials: STSAudience must be set for the GDCH auth flows")
}
signer, err := internal.ParseKey([]byte(f.PrivateKey))
pk, err := internal.ParseKey([]byte(f.PrivateKey))
if err != nil {
return nil, err
}
@@ -78,11 +75,10 @@ func NewTokenProvider(f *credsfile.GDCHServiceAccountFile, o *Options) (auth.Tok
serviceIdentity: fmt.Sprintf("system:serviceaccount:%s:%s", f.Project, f.Name),
tokenURL: f.TokenURL,
aud: o.STSAudience,
signer: signer,
pk: pk,
pkID: f.PrivateKeyID,
certPool: certPool,
client: o.Client,
logger: internallog.New(o.Logger),
}
return tp, nil
}
@@ -101,12 +97,11 @@ type gdchProvider struct {
serviceIdentity string
tokenURL string
aud string
signer crypto.Signer
pk *rsa.PrivateKey
pkID string
certPool *x509.CertPool
client *http.Client
logger *slog.Logger
}
func (g gdchProvider) Token(ctx context.Context) (*auth.Token, error) {
@@ -125,7 +120,7 @@ func (g gdchProvider) Token(ctx context.Context) (*auth.Token, error) {
Type: jwt.HeaderType,
KeyID: string(g.pkID),
}
payload, err := jwt.EncodeJWS(&h, &claims, g.signer)
payload, err := jwt.EncodeJWS(&h, &claims, g.pk)
if err != nil {
return nil, err
}
@@ -141,12 +136,10 @@ func (g gdchProvider) Token(ctx context.Context) (*auth.Token, error) {
return nil, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
g.logger.DebugContext(ctx, "gdch token request", "request", internallog.HTTPRequest(req, []byte(v.Encode())))
resp, body, err := internal.DoRequest(g.client, req)
if err != nil {
return nil, fmt.Errorf("credentials: cannot fetch token: %w", err)
}
g.logger.DebugContext(ctx, "gdch token response", "response", internallog.HTTPResponse(resp, body))
if c := resp.StatusCode; c < http.StatusOK || c > http.StatusMultipleChoices {
return nil, &auth.Error{
Response: resp,

View File

@@ -1,105 +0,0 @@
// Copyright 2025 Google LLC
//
// 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 impersonate
import (
"bytes"
"context"
"encoding/json"
"fmt"
"log/slog"
"net/http"
"strings"
"time"
"cloud.google.com/go/auth"
"cloud.google.com/go/auth/internal"
"github.com/googleapis/gax-go/v2/internallog"
)
var (
universeDomainPlaceholder = "UNIVERSE_DOMAIN"
iamCredentialsUniverseDomainEndpoint = "https://iamcredentials.UNIVERSE_DOMAIN"
)
// IDTokenIAMOptions provides configuration for [IDTokenIAMOptions.Token].
type IDTokenIAMOptions struct {
// Client is required.
Client *http.Client
// Logger is required.
Logger *slog.Logger
UniverseDomain auth.CredentialsPropertyProvider
ServiceAccountEmail string
GenerateIDTokenRequest
}
// GenerateIDTokenRequest holds the request to the IAM generateIdToken RPC.
type GenerateIDTokenRequest struct {
Audience string `json:"audience"`
IncludeEmail bool `json:"includeEmail"`
// Delegates are the ordered, fully-qualified resource name for service
// accounts in a delegation chain. Each service account must be granted
// roles/iam.serviceAccountTokenCreator on the next service account in the
// chain. The delegates must have the following format:
// projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}. The - wildcard
// character is required; replacing it with a project ID is invalid.
// Optional.
Delegates []string `json:"delegates,omitempty"`
}
// GenerateIDTokenResponse holds the response from the IAM generateIdToken RPC.
type GenerateIDTokenResponse struct {
Token string `json:"token"`
}
// Token call IAM generateIdToken with the configuration provided in [IDTokenIAMOptions].
func (o IDTokenIAMOptions) Token(ctx context.Context) (*auth.Token, error) {
universeDomain, err := o.UniverseDomain.GetProperty(ctx)
if err != nil {
return nil, err
}
endpoint := strings.Replace(iamCredentialsUniverseDomainEndpoint, universeDomainPlaceholder, universeDomain, 1)
url := fmt.Sprintf("%s/v1/%s:generateIdToken", endpoint, internal.FormatIAMServiceAccountResource(o.ServiceAccountEmail))
bodyBytes, err := json.Marshal(o.GenerateIDTokenRequest)
if err != nil {
return nil, fmt.Errorf("impersonate: unable to marshal request: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(bodyBytes))
if err != nil {
return nil, fmt.Errorf("impersonate: unable to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
o.Logger.DebugContext(ctx, "impersonated idtoken request", "request", internallog.HTTPRequest(req, bodyBytes))
resp, body, err := internal.DoRequest(o.Client, req)
if err != nil {
return nil, fmt.Errorf("impersonate: unable to generate ID token: %w", err)
}
o.Logger.DebugContext(ctx, "impersonated idtoken response", "response", internallog.HTTPResponse(resp, body))
if c := resp.StatusCode; c < 200 || c > 299 {
return nil, fmt.Errorf("impersonate: status code %d: %s", c, body)
}
var tokenResp GenerateIDTokenResponse
if err := json.Unmarshal(body, &tokenResp); err != nil {
return nil, fmt.Errorf("impersonate: unable to parse response: %w", err)
}
return &auth.Token{
Value: tokenResp.Token,
// Generated ID tokens are good for one hour.
Expiry: time.Now().Add(1 * time.Hour),
}, nil
}

View File

@@ -20,13 +20,11 @@ import (
"encoding/json"
"errors"
"fmt"
"log/slog"
"net/http"
"time"
"cloud.google.com/go/auth"
"cloud.google.com/go/auth/internal"
"github.com/googleapis/gax-go/v2/internallog"
)
const (
@@ -76,11 +74,6 @@ type Options struct {
// Client configures the underlying client used to make network requests
// when fetching tokens. Required.
Client *http.Client
// Logger is used for debug logging. If provided, logging will be enabled
// at the loggers configured level. By default logging is disabled unless
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
// logger will be used. Optional.
Logger *slog.Logger
}
func (o *Options) validate() error {
@@ -95,7 +88,6 @@ func (o *Options) validate() error {
// Token performs the exchange to get a temporary service account token to allow access to GCP.
func (o *Options) Token(ctx context.Context) (*auth.Token, error) {
logger := internallog.New(o.Logger)
lifetime := defaultTokenLifetime
if o.TokenLifetimeSeconds != 0 {
lifetime = fmt.Sprintf("%ds", o.TokenLifetimeSeconds)
@@ -117,12 +109,10 @@ func (o *Options) Token(ctx context.Context) (*auth.Token, error) {
if err := setAuthHeader(ctx, o.Tp, req); err != nil {
return nil, err
}
logger.DebugContext(ctx, "impersonated token request", "request", internallog.HTTPRequest(req, b))
resp, body, err := internal.DoRequest(o.Client, req)
if err != nil {
return nil, fmt.Errorf("credentials: unable to generate access token: %w", err)
}
logger.DebugContext(ctx, "impersonated token response", "response", internallog.HTTPResponse(resp, body))
if c := resp.StatusCode; c < http.StatusOK || c >= http.StatusMultipleChoices {
return nil, fmt.Errorf("credentials: status code %d: %s", c, body)
}

View File

@@ -19,7 +19,6 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"log/slog"
"net/http"
"net/url"
"strconv"
@@ -27,7 +26,6 @@ import (
"cloud.google.com/go/auth"
"cloud.google.com/go/auth/internal"
"github.com/googleapis/gax-go/v2/internallog"
)
const (
@@ -42,7 +40,6 @@ const (
// Options stores the configuration for making an sts exchange request.
type Options struct {
Client *http.Client
Logger *slog.Logger
Endpoint string
Request *TokenRequest
Authentication ClientAuthentication
@@ -83,7 +80,6 @@ func ExchangeToken(ctx context.Context, opts *Options) (*TokenResponse, error) {
func doRequest(ctx context.Context, opts *Options, data url.Values) (*TokenResponse, error) {
opts.Authentication.InjectAuthentication(data, opts.Headers)
encodedData := data.Encode()
logger := internallog.New(opts.Logger)
req, err := http.NewRequestWithContext(ctx, "POST", opts.Endpoint, strings.NewReader(encodedData))
if err != nil {
@@ -97,12 +93,10 @@ func doRequest(ctx context.Context, opts *Options, data url.Values) (*TokenRespo
}
req.Header.Set("Content-Length", strconv.Itoa(len(encodedData)))
logger.DebugContext(ctx, "sts token request", "request", internallog.HTTPRequest(req, []byte(encodedData)))
resp, body, err := internal.DoRequest(opts.Client, req)
if err != nil {
return nil, fmt.Errorf("credentials: invalid response from Secure Token Server: %w", err)
}
logger.DebugContext(ctx, "sts token response", "response", internallog.HTTPResponse(resp, body))
if c := resp.StatusCode; c < http.StatusOK || c > http.StatusMultipleChoices {
return nil, fmt.Errorf("credentials: status code %d: %s", c, body)
}

View File

@@ -16,10 +16,8 @@ package credentials
import (
"context"
"crypto"
"errors"
"crypto/rsa"
"fmt"
"log/slog"
"strings"
"time"
@@ -37,10 +35,7 @@ var (
// configureSelfSignedJWT uses the private key in the service account to create
// a JWT without making a network call.
func configureSelfSignedJWT(f *credsfile.ServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
if len(opts.scopes()) == 0 && opts.Audience == "" {
return nil, errors.New("credentials: both scopes and audience are empty")
}
signer, err := internal.ParseKey([]byte(f.PrivateKey))
pk, err := internal.ParseKey([]byte(f.PrivateKey))
if err != nil {
return nil, fmt.Errorf("credentials: could not parse key: %w", err)
}
@@ -48,9 +43,8 @@ func configureSelfSignedJWT(f *credsfile.ServiceAccountFile, opts *DetectOptions
email: f.ClientEmail,
audience: opts.Audience,
scopes: opts.scopes(),
signer: signer,
pk: pk,
pkID: f.PrivateKeyID,
logger: opts.logger(),
}, nil
}
@@ -58,9 +52,8 @@ type selfSignedTokenProvider struct {
email string
audience string
scopes []string
signer crypto.Signer
pk *rsa.PrivateKey
pkID string
logger *slog.Logger
}
func (tp *selfSignedTokenProvider) Token(context.Context) (*auth.Token, error) {
@@ -80,10 +73,9 @@ func (tp *selfSignedTokenProvider) Token(context.Context) (*auth.Token, error) {
Type: jwt.HeaderType,
KeyID: string(tp.pkID),
}
tok, err := jwt.EncodeJWS(h, c, tp.signer)
msg, err := jwt.EncodeJWS(h, c, tp.pk)
if err != nil {
return nil, fmt.Errorf("credentials: could not encode JWT: %w", err)
}
tp.logger.Debug("created self-signed JWT", "token", tok)
return &auth.Token{Value: tok, Type: internal.TokenTypeBearer, Expiry: exp}, nil
return &auth.Token{Value: msg, Type: internal.TokenTypeBearer, Expiry: exp}, nil
}

View File

@@ -22,7 +22,7 @@ import (
"strings"
"cloud.google.com/go/auth"
"cloud.google.com/go/auth/internal/compute"
"cloud.google.com/go/compute/metadata"
"google.golang.org/grpc"
grpcgoogle "google.golang.org/grpc/credentials/google"
)
@@ -55,7 +55,7 @@ func checkDirectPathEndPoint(endpoint string) bool {
return true
}
func isTokenProviderDirectPathCompatible(tp auth.TokenProvider, o *Options) bool {
func isTokenProviderDirectPathCompatible(tp auth.TokenProvider, _ *Options) bool {
if tp == nil {
return false
}
@@ -69,9 +69,6 @@ func isTokenProviderDirectPathCompatible(tp auth.TokenProvider, o *Options) bool
if tok.MetadataString("auth.google.tokenSource") != "compute-metadata" {
return false
}
if o.InternalOptions != nil && o.InternalOptions.EnableNonDefaultSAForDirectPath {
return true
}
if tok.MetadataString("auth.google.serviceAccount") != "default" {
return false
}
@@ -94,7 +91,7 @@ func isDirectPathXdsUsed(o *Options) bool {
// configuration allows the use of direct path. If it does not the provided
// grpcOpts and endpoint are returned.
func configureDirectPath(grpcOpts []grpc.DialOption, opts *Options, endpoint string, creds *auth.Credentials) ([]grpc.DialOption, string) {
if isDirectPathEnabled(endpoint, opts) && compute.OnComputeEngine() && isTokenProviderDirectPathCompatible(creds, opts) {
if isDirectPathEnabled(endpoint, opts) && metadata.OnGCE() && isTokenProviderDirectPathCompatible(creds, opts) {
// Overwrite all of the previously specific DialOptions, DirectPath uses its own set of credentials and certificates.
grpcOpts = []grpc.DialOption{
grpc.WithCredentialsBundle(grpcgoogle.NewDefaultCredentialsWithOptions(grpcgoogle.DefaultCredentialsOptions{PerRPCCreds: &grpcCredentialsProvider{creds: creds}}))}

View File

@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package grpctransport provides functionality for managing gRPC client
// connections to Google Cloud services.
package grpctransport
import (
@@ -21,21 +19,16 @@ import (
"crypto/tls"
"errors"
"fmt"
"log/slog"
"net/http"
"os"
"sync"
"cloud.google.com/go/auth"
"cloud.google.com/go/auth/credentials"
"cloud.google.com/go/auth/internal"
"cloud.google.com/go/auth/internal/transport"
"github.com/googleapis/gax-go/v2/internallog"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"go.opencensus.io/plugin/ocgrpc"
"google.golang.org/grpc"
grpccreds "google.golang.org/grpc/credentials"
grpcinsecure "google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/stats"
)
const (
@@ -45,7 +38,7 @@ const (
// Check env to decide if using google-c2p resolver for DirectPath traffic.
enableDirectPathXdsEnvVar = "GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS"
quotaProjectHeaderKey = "X-goog-user-project"
quotaProjectHeaderKey = "X-Goog-User-Project"
)
var (
@@ -53,27 +46,6 @@ var (
timeoutDialerOption grpc.DialOption
)
// otelStatsHandler is a singleton otelgrpc.clientHandler to be used across
// all dial connections to avoid the memory leak documented in
// https://github.com/open-telemetry/opentelemetry-go-contrib/issues/4226
//
// TODO: When this module depends on a version of otelgrpc containing the fix,
// replace this singleton with inline usage for simplicity.
// The fix should be in https://github.com/open-telemetry/opentelemetry-go/pull/5797.
var (
initOtelStatsHandlerOnce sync.Once
otelStatsHandler stats.Handler
)
// otelGRPCStatsHandler returns singleton otelStatsHandler for reuse across all
// dial connections.
func otelGRPCStatsHandler() stats.Handler {
initOtelStatsHandlerOnce.Do(func() {
otelStatsHandler = otelgrpc.NewClientHandler()
})
return otelStatsHandler
}
// ClientCertProvider is a function that returns a TLS client certificate to be
// used when opening TLS connections. It follows the same semantics as
// [crypto/tls.Config.GetClientCertificate].
@@ -118,11 +90,6 @@ type Options struct {
// APIKey specifies an API key to be used as the basis for authentication.
// If set DetectOpts are ignored.
APIKey string
// Logger is used for debug logging. If provided, logging will be enabled
// at the loggers configured level. By default logging is disabled unless
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
// logger will be used. Optional.
Logger *slog.Logger
// InternalOptions are NOT meant to be set directly by consumers of this
// package, they should only be set by generated client code.
@@ -138,10 +105,6 @@ func (o *Options) client() *http.Client {
return nil
}
func (o *Options) logger() *slog.Logger {
return internallog.New(o.Logger)
}
func (o *Options) validate() error {
if o == nil {
return errors.New("grpctransport: opts required to be non-nil")
@@ -183,9 +146,6 @@ func (o *Options) resolveDetectOptions() *credentials.DetectOptions {
do.Client = transport.DefaultHTTPClientWithTLS(tlsConfig)
do.TokenURL = credentials.GoogleMTLSTokenURL
}
if do.Logger == nil {
do.Logger = o.logger()
}
return do
}
@@ -254,7 +214,6 @@ func dial(ctx context.Context, secure bool, opts *Options) (*grpc.ClientConn, er
ClientCertProvider: opts.ClientCertProvider,
Client: opts.client(),
UniverseDomain: opts.UniverseDomain,
Logger: opts.logger(),
}
if io := opts.InternalOptions; io != nil {
tOpts.DefaultEndpointTemplate = io.DefaultEndpointTemplate
@@ -312,10 +271,7 @@ func dial(ctx context.Context, secure bool, opts *Options) (*grpc.ClientConn, er
if metadata == nil {
metadata = make(map[string]string, 1)
}
// Don't overwrite user specified quota
if _, ok := metadata[quotaProjectHeaderKey]; !ok {
metadata[quotaProjectHeaderKey] = qp
}
metadata[quotaProjectHeaderKey] = qp
}
grpcOpts = append(grpcOpts,
grpc.WithPerRPCCredentials(&grpcCredentialsProvider{
@@ -332,10 +288,10 @@ func dial(ctx context.Context, secure bool, opts *Options) (*grpc.ClientConn, er
// Add tracing, but before the other options, so that clients can override the
// gRPC stats handler.
// This assumes that gRPC options are processed in order, left to right.
grpcOpts = addOpenTelemetryStatsHandler(grpcOpts, opts)
grpcOpts = addOCStatsHandler(grpcOpts, opts)
grpcOpts = append(grpcOpts, opts.GRPCDialOpts...)
return grpc.Dial(endpoint, grpcOpts...)
return grpc.DialContext(ctx, endpoint, grpcOpts...)
}
// grpcKeyProvider satisfies https://pkg.go.dev/google.golang.org/grpc/credentials#PerRPCCredentials.
@@ -369,23 +325,15 @@ type grpcCredentialsProvider struct {
clientUniverseDomain string
}
// getClientUniverseDomain returns the default service domain for a given Cloud
// universe, with the following precedence:
//
// 1. A non-empty option.WithUniverseDomain or similar client option.
// 2. A non-empty environment variable GOOGLE_CLOUD_UNIVERSE_DOMAIN.
// 3. The default value "googleapis.com".
//
// This is the universe domain configured for the client, which will be compared
// to the universe domain that is separately configured for the credentials.
// getClientUniverseDomain returns the default service domain for a given Cloud universe.
// The default value is "googleapis.com". This is the universe domain
// configured for the client, which will be compared to the universe domain
// that is separately configured for the credentials.
func (c *grpcCredentialsProvider) getClientUniverseDomain() string {
if c.clientUniverseDomain != "" {
return c.clientUniverseDomain
if c.clientUniverseDomain == "" {
return internal.DefaultUniverseDomain
}
if envUD := os.Getenv(internal.UniverseDomainEnvVar); envUD != "" {
return envUD
}
return internal.DefaultUniverseDomain
return c.clientUniverseDomain
}
func (c *grpcCredentialsProvider) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
@@ -430,9 +378,9 @@ func (c *grpcCredentialsProvider) RequireTransportSecurity() bool {
return c.secure
}
func addOpenTelemetryStatsHandler(dialOpts []grpc.DialOption, opts *Options) []grpc.DialOption {
func addOCStatsHandler(dialOpts []grpc.DialOption, opts *Options) []grpc.DialOption {
if opts.DisableTelemetry {
return dialOpts
}
return append(dialOpts, grpc.WithStatsHandler(otelGRPCStatsHandler()))
return append(dialOpts, grpc.WithStatsHandler(&ocgrpc.ClientHandler{}))
}

View File

@@ -12,22 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package httptransport provides functionality for managing HTTP client
// connections to Google Cloud services.
package httptransport
import (
"crypto/tls"
"errors"
"fmt"
"log/slog"
"net/http"
"cloud.google.com/go/auth"
detect "cloud.google.com/go/auth/credentials"
"cloud.google.com/go/auth/internal"
"cloud.google.com/go/auth/internal/transport"
"github.com/googleapis/gax-go/v2/internallog"
)
// ClientCertProvider is a function that returns a TLS client certificate to be
@@ -71,11 +67,6 @@ type Options struct {
// configured for the client, which will be compared to the universe domain
// that is separately configured for the credentials.
UniverseDomain string
// Logger is used for debug logging. If provided, logging will be enabled
// at the loggers configured level. By default logging is disabled unless
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
// logger will be used. Optional.
Logger *slog.Logger
// InternalOptions are NOT meant to be set directly by consumers of this
// package, they should only be set by generated client code.
@@ -108,10 +99,6 @@ func (o *Options) client() *http.Client {
return nil
}
func (o *Options) logger() *slog.Logger {
return internallog.New(o.Logger)
}
func (o *Options) resolveDetectOptions() *detect.DetectOptions {
io := o.InternalOptions
// soft-clone these so we are not updating a ref the user holds and may reuse
@@ -136,9 +123,6 @@ func (o *Options) resolveDetectOptions() *detect.DetectOptions {
do.Client = transport.DefaultHTTPClientWithTLS(tlsConfig)
do.TokenURL = detect.GoogleMTLSTokenURL
}
if do.Logger == nil {
do.Logger = o.logger()
}
return do
}
@@ -161,21 +145,14 @@ type InternalOptions struct {
// service.
DefaultScopes []string
// SkipValidation bypasses validation on Options. It should only be used
// internally for clients that need more control over their transport.
// internally for clients that needs more control over their transport.
SkipValidation bool
// SkipUniverseDomainValidation skips the verification that the universe
// domain configured for the client matches the universe domain configured
// for the credentials. It should only be used internally for clients that
// need more control over their transport. The default is false.
SkipUniverseDomainValidation bool
}
// AddAuthorizationMiddleware adds a middleware to the provided client's
// transport that sets the Authorization header with the value produced by the
// provided [cloud.google.com/go/auth.Credentials]. An error is returned only
// if client or creds is nil.
//
// This function does not support setting a universe domain value on the client.
func AddAuthorizationMiddleware(client *http.Client, creds *auth.Credentials) error {
if client == nil || creds == nil {
return fmt.Errorf("httptransport: client and tp must not be nil")
@@ -194,6 +171,7 @@ func AddAuthorizationMiddleware(client *http.Client, creds *auth.Credentials) er
client.Transport = &authTransport{
creds: creds,
base: base,
// TODO(quartzmo): Somehow set clientUniverseDomain from impersonate calls.
}
return nil
}
@@ -211,7 +189,6 @@ func NewClient(opts *Options) (*http.Client, error) {
ClientCertProvider: opts.ClientCertProvider,
Client: opts.client(),
UniverseDomain: opts.UniverseDomain,
Logger: opts.logger(),
}
if io := opts.InternalOptions; io != nil {
tOpts.DefaultEndpointTemplate = io.DefaultEndpointTemplate

93
vendor/cloud.google.com/go/auth/httptransport/trace.go generated vendored Normal file
View File

@@ -0,0 +1,93 @@
// Copyright 2023 Google LLC
//
// 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 httptransport
import (
"encoding/binary"
"encoding/hex"
"fmt"
"net/http"
"strconv"
"strings"
"go.opencensus.io/trace"
"go.opencensus.io/trace/propagation"
)
const (
httpHeaderMaxSize = 200
cloudTraceHeader = `X-Cloud-Trace-Context`
)
// asserts the httpFormat fulfills this foreign interface
var _ propagation.HTTPFormat = (*httpFormat)(nil)
// httpFormat implements propagation.httpFormat to propagate
// traces in HTTP headers for Google Cloud Platform and Cloud Trace.
type httpFormat struct{}
// SpanContextFromRequest extracts a Cloud Trace span context from incoming requests.
func (f *httpFormat) SpanContextFromRequest(req *http.Request) (sc trace.SpanContext, ok bool) {
h := req.Header.Get(cloudTraceHeader)
// See https://cloud.google.com/trace/docs/faq for the header HTTPFormat.
// Return if the header is empty or missing, or if the header is unreasonably
// large, to avoid making unnecessary copies of a large string.
if h == "" || len(h) > httpHeaderMaxSize {
return trace.SpanContext{}, false
}
// Parse the trace id field.
slash := strings.Index(h, `/`)
if slash == -1 {
return trace.SpanContext{}, false
}
tid, h := h[:slash], h[slash+1:]
buf, err := hex.DecodeString(tid)
if err != nil {
return trace.SpanContext{}, false
}
copy(sc.TraceID[:], buf)
// Parse the span id field.
spanstr := h
semicolon := strings.Index(h, `;`)
if semicolon != -1 {
spanstr, h = h[:semicolon], h[semicolon+1:]
}
sid, err := strconv.ParseUint(spanstr, 10, 64)
if err != nil {
return trace.SpanContext{}, false
}
binary.BigEndian.PutUint64(sc.SpanID[:], sid)
// Parse the options field, options field is optional.
if !strings.HasPrefix(h, "o=") {
return sc, true
}
o, err := strconv.ParseUint(h[2:], 10, 32)
if err != nil {
return trace.SpanContext{}, false
}
sc.TraceOptions = trace.TraceOptions(o)
return sc, true
}
// SpanContextToRequest modifies the given request to include a Cloud Trace header.
func (f *httpFormat) SpanContextToRequest(sc trace.SpanContext, req *http.Request) {
sid := binary.BigEndian.Uint64(sc.SpanID[:])
header := fmt.Sprintf("%s/%d;o=%d", hex.EncodeToString(sc.TraceID[:]), sid, int64(sc.TraceOptions))
req.Header.Set(cloudTraceHeader, header)
}

View File

@@ -19,7 +19,6 @@ import (
"crypto/tls"
"net"
"net/http"
"os"
"time"
"cloud.google.com/go/auth"
@@ -27,12 +26,12 @@ import (
"cloud.google.com/go/auth/internal"
"cloud.google.com/go/auth/internal/transport"
"cloud.google.com/go/auth/internal/transport/cert"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opencensus.io/plugin/ochttp"
"golang.org/x/net/http2"
)
const (
quotaProjectHeaderKey = "X-goog-user-project"
quotaProjectHeaderKey = "X-Goog-User-Project"
)
func newTransport(base http.RoundTripper, opts *Options) (http.RoundTripper, error) {
@@ -42,7 +41,7 @@ func newTransport(base http.RoundTripper, opts *Options) (http.RoundTripper, err
headers: headers,
}
var trans http.RoundTripper = ht
trans = addOpenTelemetryTransport(trans, opts)
trans = addOCTransport(trans, opts)
switch {
case opts.DisableAuthentication:
// Do nothing.
@@ -77,21 +76,13 @@ func newTransport(base http.RoundTripper, opts *Options) (http.RoundTripper, err
if headers == nil {
headers = make(map[string][]string, 1)
}
// Don't overwrite user specified quota
if v := headers.Get(quotaProjectHeaderKey); v == "" {
headers.Set(quotaProjectHeaderKey, qp)
}
}
var skipUD bool
if iOpts := opts.InternalOptions; iOpts != nil {
skipUD = iOpts.SkipUniverseDomainValidation
headers.Set(quotaProjectHeaderKey, qp)
}
creds.TokenProvider = auth.NewCachedTokenProvider(creds.TokenProvider, nil)
trans = &authTransport{
base: trans,
creds: creds,
clientUniverseDomain: opts.UniverseDomain,
skipUniverseDomainValidation: skipUD,
base: trans,
creds: creds,
clientUniverseDomain: opts.UniverseDomain,
}
}
return trans, nil
@@ -103,11 +94,7 @@ func newTransport(base http.RoundTripper, opts *Options) (http.RoundTripper, err
// http.DefaultTransport.
// If TLSCertificate is available, set TLSClientConfig as well.
func defaultBaseTransport(clientCertSource cert.Provider, dialTLSContext func(context.Context, string, string) (net.Conn, error)) http.RoundTripper {
defaultTransport, ok := http.DefaultTransport.(*http.Transport)
if !ok {
defaultTransport = transport.BaseTransport()
}
trans := defaultTransport.Clone()
trans := http.DefaultTransport.(*http.Transport).Clone()
trans.MaxIdleConnsPerHost = 100
if clientCertSource != nil {
@@ -168,37 +155,29 @@ func (t *headerTransport) RoundTrip(req *http.Request) (*http.Response, error) {
return rt.RoundTrip(&newReq)
}
func addOpenTelemetryTransport(trans http.RoundTripper, opts *Options) http.RoundTripper {
func addOCTransport(trans http.RoundTripper, opts *Options) http.RoundTripper {
if opts.DisableTelemetry {
return trans
}
return otelhttp.NewTransport(trans)
return &ochttp.Transport{
Base: trans,
Propagation: &httpFormat{},
}
}
type authTransport struct {
creds *auth.Credentials
base http.RoundTripper
clientUniverseDomain string
skipUniverseDomainValidation bool
creds *auth.Credentials
base http.RoundTripper
clientUniverseDomain string
}
// getClientUniverseDomain returns the default service domain for a given Cloud
// universe, with the following precedence:
//
// 1. A non-empty option.WithUniverseDomain or similar client option.
// 2. A non-empty environment variable GOOGLE_CLOUD_UNIVERSE_DOMAIN.
// 3. The default value "googleapis.com".
//
// This is the universe domain configured for the client, which will be compared
// to the universe domain that is separately configured for the credentials.
// getClientUniverseDomain returns the universe domain configured for the client.
// The default value is "googleapis.com".
func (t *authTransport) getClientUniverseDomain() string {
if t.clientUniverseDomain != "" {
return t.clientUniverseDomain
if t.clientUniverseDomain == "" {
return internal.DefaultUniverseDomain
}
if envUD := os.Getenv(internal.UniverseDomainEnvVar); envUD != "" {
return envUD
}
return internal.DefaultUniverseDomain
return t.clientUniverseDomain
}
// RoundTrip authorizes and authenticates the request with an
@@ -218,7 +197,7 @@ func (t *authTransport) RoundTrip(req *http.Request) (*http.Response, error) {
if err != nil {
return nil, err
}
if !t.skipUniverseDomainValidation && token.MetadataString("auth.google.tokenSource") != "compute-metadata" {
if token.MetadataString("auth.google.tokenSource") != "compute-metadata" {
credentialsUniverseDomain, err := t.creds.UniverseDomain(req.Context())
if err != nil {
return nil, err

View File

@@ -1,65 +0,0 @@
// Copyright 2024 Google LLC
//
// 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 compute
import (
"log"
"runtime"
"strings"
"sync"
)
var (
vmOnGCEOnce sync.Once
vmOnGCE bool
)
// OnComputeEngine returns whether the client is running on GCE.
//
// This is a copy of the gRPC internal googlecloud.OnGCE() func at:
// https://github.com/grpc/grpc-go/blob/master/internal/googlecloud/googlecloud.go
// The functionality is similar to the metadata.OnGCE() func at:
// https://github.com/googleapis/google-cloud-go/blob/main/compute/metadata/metadata.go
// The difference is that OnComputeEngine() does not perform HTTP or DNS check on the metadata server.
// In particular, OnComputeEngine() will return false on Serverless.
func OnComputeEngine() bool {
vmOnGCEOnce.Do(func() {
mf, err := manufacturer()
if err != nil {
log.Printf("Failed to read manufacturer, vmOnGCE=false: %v", err)
return
}
vmOnGCE = isRunningOnGCE(mf, runtime.GOOS)
})
return vmOnGCE
}
// isRunningOnGCE checks whether the local system, without doing a network request, is
// running on GCP.
func isRunningOnGCE(manufacturer []byte, goos string) bool {
name := string(manufacturer)
switch goos {
case "linux":
name = strings.TrimSpace(name)
return name == "Google" || name == "Google Compute Engine"
case "windows":
name = strings.Replace(name, " ", "", -1)
name = strings.Replace(name, "\n", "", -1)
name = strings.Replace(name, "\r", "", -1)
return name == "Google"
default:
return false
}
}

View File

@@ -1,46 +0,0 @@
// Copyright 2024 Google LLC
//
// 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 compute
import (
"errors"
"os/exec"
"regexp"
"strings"
)
const (
windowsCheckCommand = "powershell.exe"
windowsCheckCommandArgs = "Get-WmiObject -Class Win32_BIOS"
powershellOutputFilter = "Manufacturer"
windowsManufacturerRegex = ":(.*)"
)
func manufacturer() ([]byte, error) {
cmd := exec.Command(windowsCheckCommand, windowsCheckCommandArgs)
out, err := cmd.Output()
if err != nil {
return nil, err
}
for _, line := range strings.Split(strings.TrimSuffix(string(out), "\n"), "\n") {
if strings.HasPrefix(line, powershellOutputFilter) {
re := regexp.MustCompile(windowsManufacturerRegex)
name := re.FindString(line)
name = strings.TrimLeft(name, ":")
return []byte(name), nil
}
}
return nil, errors.New("cannot determine the machine's manufacturer")
}

View File

@@ -16,7 +16,7 @@ package internal
import (
"context"
"crypto"
"crypto/rsa"
"crypto/x509"
"encoding/json"
"encoding/pem"
@@ -38,11 +38,8 @@ const (
// QuotaProjectEnvVar is the environment variable for setting the quota
// project.
QuotaProjectEnvVar = "GOOGLE_CLOUD_QUOTA_PROJECT"
// UniverseDomainEnvVar is the environment variable for setting the default
// service domain for a given Cloud universe.
UniverseDomainEnvVar = "GOOGLE_CLOUD_UNIVERSE_DOMAIN"
projectEnvVar = "GOOGLE_CLOUD_PROJECT"
maxBodySize = 1 << 20
projectEnvVar = "GOOGLE_CLOUD_PROJECT"
maxBodySize = 1 << 20
// DefaultUniverseDomain is the default value for universe domain.
// Universe domain is the default service domain for a given Cloud universe.
@@ -72,27 +69,25 @@ func DefaultClient() *http.Client {
}
// ParseKey converts the binary contents of a private key file
// to an crypto.Signer. It detects whether the private key is in a
// to an *rsa.PrivateKey. It detects whether the private key is in a
// PEM container or not. If so, it extracts the the private key
// from PEM container before conversion. It only supports PEM
// containers with no passphrase.
func ParseKey(key []byte) (crypto.Signer, error) {
func ParseKey(key []byte) (*rsa.PrivateKey, error) {
block, _ := pem.Decode(key)
if block != nil {
key = block.Bytes
}
var parsedKey crypto.PrivateKey
var err error
parsedKey, err = x509.ParsePKCS8PrivateKey(key)
parsedKey, err := x509.ParsePKCS8PrivateKey(key)
if err != nil {
parsedKey, err = x509.ParsePKCS1PrivateKey(key)
if err != nil {
return nil, fmt.Errorf("private key should be a PEM or plain PKCS1 or PKCS8: %w", err)
}
}
parsed, ok := parsedKey.(crypto.Signer)
parsed, ok := parsedKey.(*rsa.PrivateKey)
if !ok {
return nil, errors.New("private key is not a signer")
return nil, errors.New("private key is invalid")
}
return parsed, nil
}
@@ -181,7 +176,6 @@ func (p StaticProperty) GetProperty(context.Context) (string, error) {
// ComputeUniverseDomainProvider fetches the credentials universe domain from
// the google cloud metadata service.
type ComputeUniverseDomainProvider struct {
MetadataClient *metadata.Client
universeDomainOnce sync.Once
universeDomain string
universeDomainErr error
@@ -191,7 +185,7 @@ type ComputeUniverseDomainProvider struct {
// metadata service.
func (c *ComputeUniverseDomainProvider) GetProperty(ctx context.Context) (string, error) {
c.universeDomainOnce.Do(func() {
c.universeDomain, c.universeDomainErr = getMetadataUniverseDomain(ctx, c.MetadataClient)
c.universeDomain, c.universeDomainErr = getMetadataUniverseDomain(ctx)
})
if c.universeDomainErr != nil {
return "", c.universeDomainErr
@@ -200,14 +194,14 @@ func (c *ComputeUniverseDomainProvider) GetProperty(ctx context.Context) (string
}
// httpGetMetadataUniverseDomain is a package var for unit test substitution.
var httpGetMetadataUniverseDomain = func(ctx context.Context, client *metadata.Client) (string, error) {
var httpGetMetadataUniverseDomain = func(ctx context.Context) (string, error) {
ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
defer cancel()
return client.GetWithContext(ctx, "universe/universe-domain")
return metadata.GetWithContext(ctx, "universe/universe_domain")
}
func getMetadataUniverseDomain(ctx context.Context, client *metadata.Client) (string, error) {
universeDomain, err := httpGetMetadataUniverseDomain(ctx, client)
func getMetadataUniverseDomain(ctx context.Context) (string, error) {
universeDomain, err := httpGetMetadataUniverseDomain(ctx)
if err == nil {
return universeDomain, nil
}
@@ -217,9 +211,3 @@ func getMetadataUniverseDomain(ctx context.Context, client *metadata.Client) (st
}
return "", err
}
// FormatIAMServiceAccountResource sets a service account name in an IAM resource
// name.
func FormatIAMServiceAccountResource(name string) string {
return fmt.Sprintf("projects/-/serviceAccounts/%s", name)
}

View File

@@ -111,7 +111,7 @@ func (c *Claims) encode() (string, error) {
}
// EncodeJWS encodes the data using the provided key as a JSON web signature.
func EncodeJWS(header *Header, c *Claims, signer crypto.Signer) (string, error) {
func EncodeJWS(header *Header, c *Claims, key *rsa.PrivateKey) (string, error) {
head, err := header.encode()
if err != nil {
return "", err
@@ -123,7 +123,7 @@ func EncodeJWS(header *Header, c *Claims, signer crypto.Signer) (string, error)
ss := fmt.Sprintf("%s.%s", head, claims)
h := sha256.New()
h.Write([]byte(ss))
sig, err := signer.Sign(rand.Reader, h.Sum(nil), crypto.SHA256)
sig, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, h.Sum(nil))
if err != nil {
return "", err
}

View File

@@ -20,7 +20,6 @@ import (
"crypto/x509"
"errors"
"log"
"log/slog"
"net"
"net/http"
"net/url"
@@ -52,19 +51,22 @@ const (
mtlsMDSKey = "/run/google-mds-mtls/client.key"
)
var (
errUniverseNotSupportedMTLS = errors.New("mTLS is not supported in any universe other than googleapis.com")
)
// Options is a struct that is duplicated information from the individual
// transport packages in order to avoid cyclic deps. It correlates 1:1 with
// fields on httptransport.Options and grpctransport.Options.
type Options struct {
Endpoint string
DefaultEndpointTemplate string
DefaultMTLSEndpoint string
DefaultEndpointTemplate string
ClientCertProvider cert.Provider
Client *http.Client
UniverseDomain string
EnableDirectPath bool
EnableDirectPathXds bool
Logger *slog.Logger
}
// getUniverseDomain returns the default service domain for a given Cloud
@@ -92,16 +94,6 @@ func (o *Options) defaultEndpoint() string {
return strings.Replace(o.DefaultEndpointTemplate, universeDomainPlaceholder, o.getUniverseDomain(), 1)
}
// defaultMTLSEndpoint returns the DefaultMTLSEndpointTemplate merged with the
// universe domain if the DefaultMTLSEndpointTemplate is set, otherwise returns an
// empty string.
func (o *Options) defaultMTLSEndpoint() string {
if o.DefaultMTLSEndpoint == "" {
return ""
}
return strings.Replace(o.DefaultMTLSEndpoint, universeDomainPlaceholder, o.getUniverseDomain(), 1)
}
// mergedEndpoint merges a user-provided Endpoint of format host[:port] with the
// default endpoint.
func (o *Options) mergedEndpoint() (string, error) {
@@ -141,11 +133,7 @@ func GetGRPCTransportCredsAndEndpoint(opts *Options) (credentials.TransportCrede
transportCredsForS2A, err = loadMTLSMDSTransportCreds(mtlsMDSRoot, mtlsMDSKey)
if err != nil {
log.Printf("Loading MTLS MDS credentials failed: %v", err)
if config.s2aAddress != "" {
s2aAddr = config.s2aAddress
} else {
return defaultTransportCreds, config.endpoint, nil
}
return defaultTransportCreds, config.endpoint, nil
}
} else if config.s2aAddress != "" {
s2aAddr = config.s2aAddress
@@ -189,11 +177,7 @@ func GetHTTPTransportConfig(opts *Options) (cert.Provider, func(context.Context,
transportCredsForS2A, err = loadMTLSMDSTransportCreds(mtlsMDSRoot, mtlsMDSKey)
if err != nil {
log.Printf("Loading MTLS MDS credentials failed: %v", err)
if config.s2aAddress != "" {
s2aAddr = config.s2aAddress
} else {
return config.clientCertSource, nil, nil
}
return config.clientCertSource, nil, nil
}
} else if config.s2aAddress != "" {
s2aAddr = config.s2aAddress
@@ -264,9 +248,12 @@ func getTransportConfig(opts *Options) (*transportConfig, error) {
if !shouldUseS2A(clientCertSource, opts) {
return &defaultTransportConfig, nil
}
if !opts.isUniverseDomainGDU() {
return nil, errUniverseNotSupportedMTLS
}
s2aAddress := GetS2AAddress(opts.Logger)
mtlsS2AAddress := GetMTLSS2AAddress(opts.Logger)
s2aAddress := GetS2AAddress()
mtlsS2AAddress := GetMTLSS2AAddress()
if s2aAddress == "" && mtlsS2AAddress == "" {
return &defaultTransportConfig, nil
}
@@ -275,7 +262,7 @@ func getTransportConfig(opts *Options) (*transportConfig, error) {
endpoint: endpoint,
s2aAddress: s2aAddress,
mtlsS2AAddress: mtlsS2AAddress,
s2aMTLSEndpoint: opts.defaultMTLSEndpoint(),
s2aMTLSEndpoint: opts.DefaultMTLSEndpoint,
}, nil
}
@@ -321,23 +308,24 @@ type transportConfig struct {
// getEndpoint returns the endpoint for the service, taking into account the
// user-provided endpoint override "settings.Endpoint".
//
// If no endpoint override is specified, we will either return the default
// endpoint or the default mTLS endpoint if a client certificate is available.
// If no endpoint override is specified, we will either return the default endpoint or
// the default mTLS endpoint if a client certificate is available.
//
// You can override the default endpoint choice (mTLS vs. regular) by setting
// the GOOGLE_API_USE_MTLS_ENDPOINT environment variable.
// You can override the default endpoint choice (mtls vs. regular) by setting the
// GOOGLE_API_USE_MTLS_ENDPOINT environment variable.
//
// If the endpoint override is an address (host:port) rather than full base
// URL (ex. https://...), then the user-provided address will be merged into
// the default endpoint. For example, WithEndpoint("myhost:8000") and
// DefaultEndpointTemplate("https://UNIVERSE_DOMAIN/bar/baz") will return
// "https://myhost:8080/bar/baz". Note that this does not apply to the mTLS
// endpoint.
// DefaultEndpointTemplate("https://UNIVERSE_DOMAIN/bar/baz") will return "https://myhost:8080/bar/baz"
func getEndpoint(opts *Options, clientCertSource cert.Provider) (string, error) {
if opts.Endpoint == "" {
mtlsMode := getMTLSMode()
if mtlsMode == mTLSModeAlways || (clientCertSource != nil && mtlsMode == mTLSModeAuto) {
return opts.defaultMTLSEndpoint(), nil
if !opts.isUniverseDomainGDU() {
return "", errUniverseNotSupportedMTLS
}
return opts.DefaultMTLSEndpoint, nil
}
return opts.defaultEndpoint(), nil
}

View File

@@ -16,6 +16,7 @@ package cert
import (
"crypto/tls"
"errors"
"github.com/googleapis/enterprise-certificate-proxy/client"
)
@@ -36,9 +37,10 @@ type ecpSource struct {
func NewEnterpriseCertificateProxyProvider(configFilePath string) (Provider, error) {
key, err := client.Cred(configFilePath)
if err != nil {
// TODO(codyoss): once this is fixed upstream can handle this error a
// little better here. But be safe for now and assume unavailable.
return nil, errSourceUnavailable
if errors.Is(err, client.ErrCredUnavailable) {
return nil, errSourceUnavailable
}
return nil, err
}
return (&ecpSource{

View File

@@ -62,11 +62,11 @@ func NewSecureConnectProvider(configFilePath string) (Provider, error) {
file, err := os.ReadFile(configFilePath)
if err != nil {
// Config file missing means Secure Connect is not supported.
// There are non-os.ErrNotExist errors that may be returned.
// (e.g. if the home directory is /dev/null, *nix systems will
// return ENOTDIR instead of ENOENT)
return nil, errSourceUnavailable
if errors.Is(err, os.ErrNotExist) {
// Config file missing means Secure Connect is not supported.
return nil, errSourceUnavailable
}
return nil, err
}
var metadata secureConnectMetadata

View File

@@ -82,7 +82,10 @@ func (s *workloadSource) getClientCertificate(info *tls.CertificateRequestInfo)
func getCertAndKeyFiles(configFilePath string) (string, string, error) {
jsonFile, err := os.Open(configFilePath)
if err != nil {
return "", "", errSourceUnavailable
if errors.Is(err, os.ErrNotExist) {
return "", "", errSourceUnavailable
}
return "", "", err
}
byteValue, err := io.ReadAll(jsonFile)

View File

@@ -15,11 +15,9 @@
package transport
import (
"context"
"encoding/json"
"fmt"
"log"
"log/slog"
"os"
"strconv"
"sync"
@@ -40,8 +38,8 @@ var (
// GetS2AAddress returns the S2A address to be reached via plaintext connection.
// Returns empty string if not set or invalid.
func GetS2AAddress(logger *slog.Logger) string {
getMetadataMTLSAutoConfig(logger)
func GetS2AAddress() string {
getMetadataMTLSAutoConfig()
if !mtlsConfiguration.valid() {
return ""
}
@@ -50,8 +48,8 @@ func GetS2AAddress(logger *slog.Logger) string {
// GetMTLSS2AAddress returns the S2A address to be reached via MTLS connection.
// Returns empty string if not set or invalid.
func GetMTLSS2AAddress(logger *slog.Logger) string {
getMetadataMTLSAutoConfig(logger)
func GetMTLSS2AAddress() string {
getMetadataMTLSAutoConfig()
if !mtlsConfiguration.valid() {
return ""
}
@@ -75,25 +73,22 @@ type s2aAddresses struct {
MTLSAddress string `json:"mtls_address"`
}
func getMetadataMTLSAutoConfig(logger *slog.Logger) {
func getMetadataMTLSAutoConfig() {
var err error
mtlsOnce.Do(func() {
mtlsConfiguration, err = queryConfig(logger)
mtlsConfiguration, err = queryConfig()
if err != nil {
log.Printf("Getting MTLS config failed: %v", err)
}
})
}
var httpGetMetadataMTLSConfig = func(logger *slog.Logger) (string, error) {
metadataClient := metadata.NewWithOptions(&metadata.Options{
Logger: logger,
})
return metadataClient.GetWithContext(context.Background(), configEndpointSuffix)
var httpGetMetadataMTLSConfig = func() (string, error) {
return metadata.Get(configEndpointSuffix)
}
func queryConfig(logger *slog.Logger) (*mtlsConfig, error) {
resp, err := httpGetMetadataMTLSConfig(logger)
func queryConfig() (*mtlsConfig, error) {
resp, err := httpGetMetadataMTLSConfig()
if err != nil {
return nil, fmt.Errorf("querying MTLS config from MDS endpoint failed: %w", err)
}

View File

@@ -49,7 +49,6 @@ func CloneDetectOptions(oldDo *credentials.DetectOptions) *credentials.DetectOpt
// These fields are are pointer types that we just want to use exactly
// as the user set, copy the ref
Client: oldDo.Client,
Logger: oldDo.Logger,
AuthHandlerOptions: oldDo.AuthHandlerOptions,
}
@@ -82,14 +81,12 @@ func ValidateUniverseDomain(clientUniverseDomain, credentialsUniverseDomain stri
// DefaultHTTPClientWithTLS constructs an HTTPClient using the provided tlsConfig, to support mTLS.
func DefaultHTTPClientWithTLS(tlsConfig *tls.Config) *http.Client {
trans := BaseTransport()
trans := baseTransport()
trans.TLSClientConfig = tlsConfig
return &http.Client{Transport: trans}
}
// BaseTransport returns a default [http.Transport] which can be used if
// [http.DefaultTransport] has been overwritten.
func BaseTransport() *http.Transport {
func baseTransport() *http.Transport {
return &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{

View File

@@ -1,26 +1,5 @@
# Changelog
## [0.2.7](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.6...auth/oauth2adapt/v0.2.7) (2025-01-09)
### Bug Fixes
* **auth/oauth2adapt:** Update golang.org/x/net to v0.33.0 ([e9b0b69](https://github.com/googleapis/google-cloud-go/commit/e9b0b69644ea5b276cacff0a707e8a5e87efafc9))
## [0.2.6](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.5...auth/oauth2adapt/v0.2.6) (2024-11-21)
### Bug Fixes
* **auth/oauth2adapt:** Copy map in tokenSourceAdapter.Token ([#11164](https://github.com/googleapis/google-cloud-go/issues/11164)) ([8cb0cbc](https://github.com/googleapis/google-cloud-go/commit/8cb0cbccdc32886dfb3af49fee04012937d114d2)), refs [#11161](https://github.com/googleapis/google-cloud-go/issues/11161)
## [0.2.5](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.4...auth/oauth2adapt/v0.2.5) (2024-10-30)
### Bug Fixes
* **auth/oauth2adapt:** Convert token metadata where possible ([#11062](https://github.com/googleapis/google-cloud-go/issues/11062)) ([34bf1c1](https://github.com/googleapis/google-cloud-go/commit/34bf1c164465d66745c0cfdf7cd10a8e2da92e52))
## [0.2.4](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.3...auth/oauth2adapt/v0.2.4) (2024-08-08)

View File

@@ -26,13 +26,6 @@ import (
"golang.org/x/oauth2/google"
)
const (
oauth2TokenSourceKey = "oauth2.google.tokenSource"
oauth2ServiceAccountKey = "oauth2.google.serviceAccount"
authTokenSourceKey = "auth.google.tokenSource"
authServiceAccountKey = "auth.google.serviceAccount"
)
// TokenProviderFromTokenSource converts any [golang.org/x/oauth2.TokenSource]
// into a [cloud.google.com/go/auth.TokenProvider].
func TokenProviderFromTokenSource(ts oauth2.TokenSource) auth.TokenProvider {
@@ -54,21 +47,10 @@ func (tp *tokenProviderAdapter) Token(context.Context) (*auth.Token, error) {
}
return nil, err
}
// Preserve compute token metadata, for both types of tokens.
metadata := map[string]interface{}{}
if val, ok := tok.Extra(oauth2TokenSourceKey).(string); ok {
metadata[authTokenSourceKey] = val
metadata[oauth2TokenSourceKey] = val
}
if val, ok := tok.Extra(oauth2ServiceAccountKey).(string); ok {
metadata[authServiceAccountKey] = val
metadata[oauth2ServiceAccountKey] = val
}
return &auth.Token{
Value: tok.AccessToken,
Type: tok.Type(),
Expiry: tok.Expiry,
Metadata: metadata,
Value: tok.AccessToken,
Type: tok.Type(),
Expiry: tok.Expiry,
}, nil
}
@@ -94,29 +76,11 @@ func (ts *tokenSourceAdapter) Token() (*oauth2.Token, error) {
}
return nil, err
}
tok2 := &oauth2.Token{
return &oauth2.Token{
AccessToken: tok.Value,
TokenType: tok.Type,
Expiry: tok.Expiry,
}
// Preserve token metadata.
m := tok.Metadata
if m != nil {
// Copy map to avoid concurrent map writes error (#11161).
metadata := make(map[string]interface{}, len(m)+2)
for k, v := range m {
metadata[k] = v
}
// Append compute token metadata in converted form.
if val, ok := metadata[authTokenSourceKey].(string); ok && val != "" {
metadata[oauth2TokenSourceKey] = val
}
if val, ok := metadata[authServiceAccountKey].(string); ok && val != "" {
metadata[oauth2ServiceAccountKey] = val
}
tok2 = tok2.WithExtra(metadata)
}
return tok2, nil
}, nil
}
// AuthCredentialsFromOauth2Credentials converts a [golang.org/x/oauth2/google.Credentials]

View File

@@ -20,7 +20,6 @@ import (
"encoding/json"
"errors"
"fmt"
"log/slog"
"mime"
"net/http"
"net/url"
@@ -29,7 +28,6 @@ import (
"time"
"cloud.google.com/go/auth/internal"
"github.com/googleapis/gax-go/v2/internallog"
)
// AuthorizationHandler is a 3-legged-OAuth helper that prompts the user for
@@ -71,11 +69,6 @@ type Options3LO struct {
// AuthHandlerOpts provides a set of options for doing a
// 3-legged OAuth2 flow with a custom [AuthorizationHandler]. Optional.
AuthHandlerOpts *AuthorizationHandlerOptions
// Logger is used for debug logging. If provided, logging will be enabled
// at the loggers configured level. By default logging is disabled unless
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
// logger will be used. Optional.
Logger *slog.Logger
}
func (o *Options3LO) validate() error {
@@ -103,10 +96,6 @@ func (o *Options3LO) validate() error {
return nil
}
func (o *Options3LO) logger() *slog.Logger {
return internallog.New(o.Logger)
}
// PKCEOptions holds parameters to support PKCE.
type PKCEOptions struct {
// Challenge is the un-padded, base64-url-encoded string of the encrypted code verifier.
@@ -304,15 +293,12 @@ func fetchToken(ctx context.Context, o *Options3LO, v url.Values) (*Token, strin
if o.AuthStyle == StyleInHeader {
req.SetBasicAuth(url.QueryEscape(o.ClientID), url.QueryEscape(o.ClientSecret))
}
logger := o.logger()
logger.DebugContext(ctx, "3LO token request", "request", internallog.HTTPRequest(req, []byte(v.Encode())))
// Make request
resp, body, err := internal.DoRequest(o.client(), req)
if err != nil {
return nil, refreshToken, err
}
logger.DebugContext(ctx, "3LO token response", "response", internallog.HTTPResponse(resp, body))
failureStatus := resp.StatusCode < 200 || resp.StatusCode > 299
tokError := &Error{
Response: resp,

View File

@@ -1,35 +1,6 @@
# Changes
## [1.3.1](https://github.com/googleapis/google-cloud-go/compare/iam/v1.3.0...iam/v1.3.1) (2025-01-02)
### Bug Fixes
* **iam:** Update golang.org/x/net to v0.33.0 ([e9b0b69](https://github.com/googleapis/google-cloud-go/commit/e9b0b69644ea5b276cacff0a707e8a5e87efafc9))
## [1.3.0](https://github.com/googleapis/google-cloud-go/compare/iam/v1.2.2...iam/v1.3.0) (2024-12-04)
### Features
* **iam:** Add ResourcePolicyMember to google/iam/v1 ([8dedb87](https://github.com/googleapis/google-cloud-go/commit/8dedb878c070cc1e92d62bb9b32358425e3ceffb))
## [1.2.2](https://github.com/googleapis/google-cloud-go/compare/iam/v1.2.1...iam/v1.2.2) (2024-10-23)
### Bug Fixes
* **iam:** Update google.golang.org/api to v0.203.0 ([8bb87d5](https://github.com/googleapis/google-cloud-go/commit/8bb87d56af1cba736e0fe243979723e747e5e11e))
* **iam:** WARNING: On approximately Dec 1, 2024, an update to Protobuf will change service registration function signatures to use an interface instead of a concrete type in generated .pb.go files. This change is expected to affect very few if any users of this client library. For more information, see https://togithub.com/googleapis/google-cloud-go/issues/11020. ([8bb87d5](https://github.com/googleapis/google-cloud-go/commit/8bb87d56af1cba736e0fe243979723e747e5e11e))
## [1.2.1](https://github.com/googleapis/google-cloud-go/compare/iam/v1.2.0...iam/v1.2.1) (2024-09-12)
### Bug Fixes
* **iam:** Bump dependencies ([2ddeb15](https://github.com/googleapis/google-cloud-go/commit/2ddeb1544a53188a7592046b98913982f1b0cf04))
## [1.2.0](https://github.com/googleapis/google-cloud-go/compare/iam/v1.1.13...iam/v1.2.0) (2024-08-20)

View File

@@ -14,7 +14,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.35.2
// protoc-gen-go v1.34.2
// protoc v4.25.3
// source: google/iam/v1/iam_policy.proto
@@ -65,9 +65,11 @@ type SetIamPolicyRequest struct {
func (x *SetIamPolicyRequest) Reset() {
*x = SetIamPolicyRequest{}
mi := &file_google_iam_v1_iam_policy_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
if protoimpl.UnsafeEnabled {
mi := &file_google_iam_v1_iam_policy_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SetIamPolicyRequest) String() string {
@@ -78,7 +80,7 @@ func (*SetIamPolicyRequest) ProtoMessage() {}
func (x *SetIamPolicyRequest) ProtoReflect() protoreflect.Message {
mi := &file_google_iam_v1_iam_policy_proto_msgTypes[0]
if x != nil {
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -130,9 +132,11 @@ type GetIamPolicyRequest struct {
func (x *GetIamPolicyRequest) Reset() {
*x = GetIamPolicyRequest{}
mi := &file_google_iam_v1_iam_policy_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
if protoimpl.UnsafeEnabled {
mi := &file_google_iam_v1_iam_policy_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetIamPolicyRequest) String() string {
@@ -143,7 +147,7 @@ func (*GetIamPolicyRequest) ProtoMessage() {}
func (x *GetIamPolicyRequest) ProtoReflect() protoreflect.Message {
mi := &file_google_iam_v1_iam_policy_proto_msgTypes[1]
if x != nil {
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -190,9 +194,11 @@ type TestIamPermissionsRequest struct {
func (x *TestIamPermissionsRequest) Reset() {
*x = TestIamPermissionsRequest{}
mi := &file_google_iam_v1_iam_policy_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
if protoimpl.UnsafeEnabled {
mi := &file_google_iam_v1_iam_policy_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TestIamPermissionsRequest) String() string {
@@ -203,7 +209,7 @@ func (*TestIamPermissionsRequest) ProtoMessage() {}
func (x *TestIamPermissionsRequest) ProtoReflect() protoreflect.Message {
mi := &file_google_iam_v1_iam_policy_proto_msgTypes[2]
if x != nil {
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -245,9 +251,11 @@ type TestIamPermissionsResponse struct {
func (x *TestIamPermissionsResponse) Reset() {
*x = TestIamPermissionsResponse{}
mi := &file_google_iam_v1_iam_policy_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
if protoimpl.UnsafeEnabled {
mi := &file_google_iam_v1_iam_policy_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TestIamPermissionsResponse) String() string {
@@ -258,7 +266,7 @@ func (*TestIamPermissionsResponse) ProtoMessage() {}
func (x *TestIamPermissionsResponse) ProtoReflect() protoreflect.Message {
mi := &file_google_iam_v1_iam_policy_proto_msgTypes[3]
if x != nil {
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -355,15 +363,16 @@ var file_google_iam_v1_iam_policy_proto_rawDesc = []byte{
0x65, 0x3d, 0x2a, 0x2a, 0x7d, 0x3a, 0x74, 0x65, 0x73, 0x74, 0x49, 0x61, 0x6d, 0x50, 0x65, 0x72,
0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x1e, 0xca, 0x41, 0x1b, 0x69, 0x61, 0x6d,
0x2d, 0x6d, 0x65, 0x74, 0x61, 0x2d, 0x61, 0x70, 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x42, 0x7c, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x2e,
0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x42, 0x7f, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x49,
0x61, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a,
0x29, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x31, 0x2f, 0x69,
0x61, 0x6d, 0x70, 0x62, 0x3b, 0x69, 0x61, 0x6d, 0x70, 0x62, 0xaa, 0x02, 0x13, 0x47, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x49, 0x61, 0x6d, 0x2e, 0x56, 0x31,
0xca, 0x02, 0x13, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c,
0x49, 0x61, 0x6d, 0x5c, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x61, 0x6d, 0x70, 0x62, 0x3b, 0x69, 0x61, 0x6d, 0x70, 0x62, 0xf8, 0x01, 0x01, 0xaa, 0x02, 0x13,
0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x49, 0x61, 0x6d,
0x2e, 0x56, 0x31, 0xca, 0x02, 0x13, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f,
0x75, 0x64, 0x5c, 0x49, 0x61, 0x6d, 0x5c, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
@@ -412,6 +421,56 @@ func file_google_iam_v1_iam_policy_proto_init() {
}
file_google_iam_v1_options_proto_init()
file_google_iam_v1_policy_proto_init()
if !protoimpl.UnsafeEnabled {
file_google_iam_v1_iam_policy_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*SetIamPolicyRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_google_iam_v1_iam_policy_proto_msgTypes[1].Exporter = func(v any, i int) any {
switch v := v.(*GetIamPolicyRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_google_iam_v1_iam_policy_proto_msgTypes[2].Exporter = func(v any, i int) any {
switch v := v.(*TestIamPermissionsRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_google_iam_v1_iam_policy_proto_msgTypes[3].Exporter = func(v any, i int) any {
switch v := v.(*TestIamPermissionsResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{

View File

@@ -14,7 +14,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.35.2
// protoc-gen-go v1.34.2
// protoc v4.25.3
// source: google/iam/v1/options.proto
@@ -64,9 +64,11 @@ type GetPolicyOptions struct {
func (x *GetPolicyOptions) Reset() {
*x = GetPolicyOptions{}
mi := &file_google_iam_v1_options_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
if protoimpl.UnsafeEnabled {
mi := &file_google_iam_v1_options_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetPolicyOptions) String() string {
@@ -77,7 +79,7 @@ func (*GetPolicyOptions) ProtoMessage() {}
func (x *GetPolicyOptions) ProtoReflect() protoreflect.Message {
mi := &file_google_iam_v1_options_proto_msgTypes[0]
if x != nil {
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -150,6 +152,20 @@ func file_google_iam_v1_options_proto_init() {
if File_google_iam_v1_options_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_google_iam_v1_options_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*GetPolicyOptions); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{

View File

@@ -14,7 +14,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.35.2
// protoc-gen-go v1.34.2
// protoc v4.25.3
// source: google/iam/v1/policy.proto
@@ -337,9 +337,11 @@ type Policy struct {
func (x *Policy) Reset() {
*x = Policy{}
mi := &file_google_iam_v1_policy_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
if protoimpl.UnsafeEnabled {
mi := &file_google_iam_v1_policy_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Policy) String() string {
@@ -350,7 +352,7 @@ func (*Policy) ProtoMessage() {}
func (x *Policy) ProtoReflect() protoreflect.Message {
mi := &file_google_iam_v1_policy_proto_msgTypes[0]
if x != nil {
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -460,9 +462,11 @@ type Binding struct {
func (x *Binding) Reset() {
*x = Binding{}
mi := &file_google_iam_v1_policy_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
if protoimpl.UnsafeEnabled {
mi := &file_google_iam_v1_policy_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Binding) String() string {
@@ -473,7 +477,7 @@ func (*Binding) ProtoMessage() {}
func (x *Binding) ProtoReflect() protoreflect.Message {
mi := &file_google_iam_v1_policy_proto_msgTypes[1]
if x != nil {
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -575,9 +579,11 @@ type AuditConfig struct {
func (x *AuditConfig) Reset() {
*x = AuditConfig{}
mi := &file_google_iam_v1_policy_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
if protoimpl.UnsafeEnabled {
mi := &file_google_iam_v1_policy_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AuditConfig) String() string {
@@ -588,7 +594,7 @@ func (*AuditConfig) ProtoMessage() {}
func (x *AuditConfig) ProtoReflect() protoreflect.Message {
mi := &file_google_iam_v1_policy_proto_msgTypes[2]
if x != nil {
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -652,9 +658,11 @@ type AuditLogConfig struct {
func (x *AuditLogConfig) Reset() {
*x = AuditLogConfig{}
mi := &file_google_iam_v1_policy_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
if protoimpl.UnsafeEnabled {
mi := &file_google_iam_v1_policy_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AuditLogConfig) String() string {
@@ -665,7 +673,7 @@ func (*AuditLogConfig) ProtoMessage() {}
func (x *AuditLogConfig) ProtoReflect() protoreflect.Message {
mi := &file_google_iam_v1_policy_proto_msgTypes[3]
if x != nil {
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -708,9 +716,11 @@ type PolicyDelta struct {
func (x *PolicyDelta) Reset() {
*x = PolicyDelta{}
mi := &file_google_iam_v1_policy_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
if protoimpl.UnsafeEnabled {
mi := &file_google_iam_v1_policy_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PolicyDelta) String() string {
@@ -721,7 +731,7 @@ func (*PolicyDelta) ProtoMessage() {}
func (x *PolicyDelta) ProtoReflect() protoreflect.Message {
mi := &file_google_iam_v1_policy_proto_msgTypes[4]
if x != nil {
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -774,9 +784,11 @@ type BindingDelta struct {
func (x *BindingDelta) Reset() {
*x = BindingDelta{}
mi := &file_google_iam_v1_policy_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
if protoimpl.UnsafeEnabled {
mi := &file_google_iam_v1_policy_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *BindingDelta) String() string {
@@ -787,7 +799,7 @@ func (*BindingDelta) ProtoMessage() {}
func (x *BindingDelta) ProtoReflect() protoreflect.Message {
mi := &file_google_iam_v1_policy_proto_msgTypes[5]
if x != nil {
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -857,9 +869,11 @@ type AuditConfigDelta struct {
func (x *AuditConfigDelta) Reset() {
*x = AuditConfigDelta{}
mi := &file_google_iam_v1_policy_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
if protoimpl.UnsafeEnabled {
mi := &file_google_iam_v1_policy_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AuditConfigDelta) String() string {
@@ -870,7 +884,7 @@ func (*AuditConfigDelta) ProtoMessage() {}
func (x *AuditConfigDelta) ProtoReflect() protoreflect.Message {
mi := &file_google_iam_v1_policy_proto_msgTypes[6]
if x != nil {
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1058,6 +1072,92 @@ func file_google_iam_v1_policy_proto_init() {
if File_google_iam_v1_policy_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_google_iam_v1_policy_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*Policy); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_google_iam_v1_policy_proto_msgTypes[1].Exporter = func(v any, i int) any {
switch v := v.(*Binding); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_google_iam_v1_policy_proto_msgTypes[2].Exporter = func(v any, i int) any {
switch v := v.(*AuditConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_google_iam_v1_policy_proto_msgTypes[3].Exporter = func(v any, i int) any {
switch v := v.(*AuditLogConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_google_iam_v1_policy_proto_msgTypes[4].Exporter = func(v any, i int) any {
switch v := v.(*PolicyDelta); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_google_iam_v1_policy_proto_msgTypes[5].Exporter = func(v any, i int) any {
switch v := v.(*BindingDelta); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_google_iam_v1_policy_proto_msgTypes[6].Exporter = func(v any, i int) any {
switch v := v.(*AuditConfigDelta); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{

View File

@@ -1,185 +0,0 @@
// Copyright 2024 Google LLC
//
// 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.
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.35.2
// protoc v4.25.3
// source: google/iam/v1/resource_policy_member.proto
package iampb
import (
reflect "reflect"
sync "sync"
_ "google.golang.org/genproto/googleapis/api/annotations"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// Output-only policy member strings of a Google Cloud resource's built-in
// identity.
type ResourcePolicyMember struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// IAM policy binding member referring to a Google Cloud resource by
// user-assigned name (https://google.aip.dev/122). If a resource is deleted
// and recreated with the same name, the binding will be applicable to the new
// resource.
//
// Example:
// `principal://parametermanager.googleapis.com/projects/12345/name/locations/us-central1-a/parameters/my-parameter`
IamPolicyNamePrincipal string `protobuf:"bytes,1,opt,name=iam_policy_name_principal,json=iamPolicyNamePrincipal,proto3" json:"iam_policy_name_principal,omitempty"`
// IAM policy binding member referring to a Google Cloud resource by
// system-assigned unique identifier (https://google.aip.dev/148#uid). If a
// resource is deleted and recreated with the same name, the binding will not
// be applicable to the new resource
//
// Example:
// `principal://parametermanager.googleapis.com/projects/12345/uid/locations/us-central1-a/parameters/a918fed5`
IamPolicyUidPrincipal string `protobuf:"bytes,2,opt,name=iam_policy_uid_principal,json=iamPolicyUidPrincipal,proto3" json:"iam_policy_uid_principal,omitempty"`
}
func (x *ResourcePolicyMember) Reset() {
*x = ResourcePolicyMember{}
mi := &file_google_iam_v1_resource_policy_member_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ResourcePolicyMember) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ResourcePolicyMember) ProtoMessage() {}
func (x *ResourcePolicyMember) ProtoReflect() protoreflect.Message {
mi := &file_google_iam_v1_resource_policy_member_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ResourcePolicyMember.ProtoReflect.Descriptor instead.
func (*ResourcePolicyMember) Descriptor() ([]byte, []int) {
return file_google_iam_v1_resource_policy_member_proto_rawDescGZIP(), []int{0}
}
func (x *ResourcePolicyMember) GetIamPolicyNamePrincipal() string {
if x != nil {
return x.IamPolicyNamePrincipal
}
return ""
}
func (x *ResourcePolicyMember) GetIamPolicyUidPrincipal() string {
if x != nil {
return x.IamPolicyUidPrincipal
}
return ""
}
var File_google_iam_v1_resource_policy_member_proto protoreflect.FileDescriptor
var file_google_iam_v1_resource_policy_member_proto_rawDesc = []byte{
0x0a, 0x2a, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x76, 0x31, 0x2f,
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f,
0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65,
0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x94, 0x01, 0x0a,
0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4d,
0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x19, 0x69, 0x61, 0x6d, 0x5f, 0x70, 0x6f, 0x6c,
0x69, 0x63, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70,
0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x16, 0x69,
0x61, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x50, 0x72, 0x69, 0x6e,
0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x3c, 0x0a, 0x18, 0x69, 0x61, 0x6d, 0x5f, 0x70, 0x6f, 0x6c,
0x69, 0x63, 0x79, 0x5f, 0x75, 0x69, 0x64, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61,
0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x15, 0x69, 0x61,
0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x69, 0x64, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69,
0x70, 0x61, 0x6c, 0x42, 0x87, 0x01, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x42, 0x19, 0x52, 0x65, 0x73, 0x6f, 0x75,
0x72, 0x63, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50,
0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x29, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x69, 0x61, 0x6d, 0x2f,
0x61, 0x70, 0x69, 0x76, 0x31, 0x2f, 0x69, 0x61, 0x6d, 0x70, 0x62, 0x3b, 0x69, 0x61, 0x6d, 0x70,
0x62, 0xaa, 0x02, 0x13, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64,
0x2e, 0x49, 0x61, 0x6d, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x13, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x49, 0x61, 0x6d, 0x5c, 0x56, 0x31, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_google_iam_v1_resource_policy_member_proto_rawDescOnce sync.Once
file_google_iam_v1_resource_policy_member_proto_rawDescData = file_google_iam_v1_resource_policy_member_proto_rawDesc
)
func file_google_iam_v1_resource_policy_member_proto_rawDescGZIP() []byte {
file_google_iam_v1_resource_policy_member_proto_rawDescOnce.Do(func() {
file_google_iam_v1_resource_policy_member_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_iam_v1_resource_policy_member_proto_rawDescData)
})
return file_google_iam_v1_resource_policy_member_proto_rawDescData
}
var file_google_iam_v1_resource_policy_member_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_google_iam_v1_resource_policy_member_proto_goTypes = []any{
(*ResourcePolicyMember)(nil), // 0: google.iam.v1.ResourcePolicyMember
}
var file_google_iam_v1_resource_policy_member_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_google_iam_v1_resource_policy_member_proto_init() }
func file_google_iam_v1_resource_policy_member_proto_init() {
if File_google_iam_v1_resource_policy_member_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_google_iam_v1_resource_policy_member_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_google_iam_v1_resource_policy_member_proto_goTypes,
DependencyIndexes: file_google_iam_v1_resource_policy_member_proto_depIdxs,
MessageInfos: file_google_iam_v1_resource_policy_member_proto_msgTypes,
}.Build()
File_google_iam_v1_resource_policy_member_proto = out.File
file_google_iam_v1_resource_policy_member_proto_rawDesc = nil
file_google_iam_v1_resource_policy_member_proto_goTypes = nil
file_google_iam_v1_resource_policy_member_proto_depIdxs = nil
}

View File

@@ -179,16 +179,6 @@
"release_level": "stable",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/apihub/apiv1": {
"api_shortname": "apihub",
"distribution_name": "cloud.google.com/go/apihub/apiv1",
"description": "API hub API",
"language": "go",
"client_library_type": "generated",
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/apihub/latest/apiv1",
"release_level": "preview",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/apikeys/apiv2": {
"api_shortname": "apikeys",
"distribution_name": "cloud.google.com/go/apikeys/apiv2",
@@ -569,16 +559,6 @@
"release_level": "stable",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/bigquery/storage/apiv1alpha": {
"api_shortname": "bigquerystorage",
"distribution_name": "cloud.google.com/go/bigquery/storage/apiv1alpha",
"description": "BigQuery Storage API",
"language": "go",
"client_library_type": "generated",
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigquery/latest/storage/apiv1alpha",
"release_level": "preview",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/bigquery/storage/apiv1beta1": {
"api_shortname": "bigquerystorage",
"distribution_name": "cloud.google.com/go/bigquery/storage/apiv1beta1",
@@ -1029,16 +1009,6 @@
"release_level": "stable",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/datastore/apiv1": {
"api_shortname": "datastore",
"distribution_name": "cloud.google.com/go/datastore/apiv1",
"description": "Cloud Datastore API",
"language": "go",
"client_library_type": "generated",
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/datastore/latest/apiv1",
"release_level": "stable",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/datastream/apiv1": {
"api_shortname": "datastream",
"distribution_name": "cloud.google.com/go/datastream/apiv1",
@@ -1359,16 +1329,6 @@
"release_level": "stable",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/gkeconnect/gateway/apiv1": {
"api_shortname": "connectgateway",
"distribution_name": "cloud.google.com/go/gkeconnect/gateway/apiv1",
"description": "Connect Gateway API",
"language": "go",
"client_library_type": "generated",
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/gkeconnect/latest/gateway/apiv1",
"release_level": "preview",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/gkeconnect/gateway/apiv1beta1": {
"api_shortname": "connectgateway",
"distribution_name": "cloud.google.com/go/gkeconnect/gateway/apiv1beta1",
@@ -1392,7 +1352,7 @@
"cloud.google.com/go/gkemulticloud/apiv1": {
"api_shortname": "gkemulticloud",
"distribution_name": "cloud.google.com/go/gkemulticloud/apiv1",
"description": "GKE Multi-Cloud API",
"description": "Anthos Multi-Cloud API",
"language": "go",
"client_library_type": "generated",
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/gkemulticloud/latest/apiv1",
@@ -1592,7 +1552,7 @@
"cloud.google.com/go/managedkafka/apiv1": {
"api_shortname": "managedkafka",
"distribution_name": "cloud.google.com/go/managedkafka/apiv1",
"description": "Managed Service for Apache Kafka API",
"description": "Apache Kafka for BigQuery API",
"language": "go",
"client_library_type": "generated",
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/managedkafka/latest/apiv1",
@@ -1609,16 +1569,6 @@
"release_level": "stable",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/maps/areainsights/apiv1": {
"api_shortname": "areainsights",
"distribution_name": "cloud.google.com/go/maps/areainsights/apiv1",
"description": "Places Insights API",
"language": "go",
"client_library_type": "generated",
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/maps/latest/areainsights/apiv1",
"release_level": "preview",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/maps/fleetengine/apiv1": {
"api_shortname": "fleetengine",
"distribution_name": "cloud.google.com/go/maps/fleetengine/apiv1",
@@ -1709,26 +1659,6 @@
"release_level": "preview",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/memorystore/apiv1": {
"api_shortname": "memorystore",
"distribution_name": "cloud.google.com/go/memorystore/apiv1",
"description": "Memorystore API",
"language": "go",
"client_library_type": "generated",
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/memorystore/latest/apiv1",
"release_level": "preview",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/memorystore/apiv1beta": {
"api_shortname": "memorystore",
"distribution_name": "cloud.google.com/go/memorystore/apiv1beta",
"description": "Memorystore API",
"language": "go",
"client_library_type": "generated",
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/memorystore/latest/apiv1beta",
"release_level": "preview",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/metastore/apiv1": {
"api_shortname": "metastore",
"distribution_name": "cloud.google.com/go/metastore/apiv1",
@@ -1776,7 +1706,7 @@
"language": "go",
"client_library_type": "generated",
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/monitoring/latest/apiv3/v2",
"release_level": "preview",
"release_level": "stable",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/monitoring/dashboard/apiv1": {
@@ -1899,16 +1829,6 @@
"release_level": "stable",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/oracledatabase/apiv1": {
"api_shortname": "oracledatabase",
"distribution_name": "cloud.google.com/go/oracledatabase/apiv1",
"description": "Oracle Database@Google Cloud API",
"language": "go",
"client_library_type": "generated",
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/oracledatabase/latest/apiv1",
"release_level": "preview",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/orchestration/airflow/service/apiv1": {
"api_shortname": "composer",
"distribution_name": "cloud.google.com/go/orchestration/airflow/service/apiv1",
@@ -1999,16 +1919,6 @@
"release_level": "preview",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/parallelstore/apiv1": {
"api_shortname": "parallelstore",
"distribution_name": "cloud.google.com/go/parallelstore/apiv1",
"description": "Parallelstore API",
"language": "go",
"client_library_type": "generated",
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/parallelstore/latest/apiv1",
"release_level": "preview",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/parallelstore/apiv1beta": {
"api_shortname": "parallelstore",
"distribution_name": "cloud.google.com/go/parallelstore/apiv1beta",
@@ -2432,7 +2342,7 @@
"cloud.google.com/go/securitycentermanagement/apiv1": {
"api_shortname": "securitycentermanagement",
"distribution_name": "cloud.google.com/go/securitycentermanagement/apiv1",
"description": "Security Command Center Management API",
"description": "Security Center Management API",
"language": "go",
"client_library_type": "generated",
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/securitycentermanagement/latest/apiv1",
@@ -2629,16 +2539,6 @@
"release_level": "preview",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/shopping/merchant/reviews/apiv1beta": {
"api_shortname": "merchantapi",
"distribution_name": "cloud.google.com/go/shopping/merchant/reviews/apiv1beta",
"description": "Merchant API",
"language": "go",
"client_library_type": "generated",
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/shopping/latest/merchant/reviews/apiv1beta",
"release_level": "preview",
"library_type": "GAPIC_AUTO"
},
"cloud.google.com/go/spanner": {
"api_shortname": "spanner",
"distribution_name": "cloud.google.com/go/spanner",

View File

@@ -18,39 +18,143 @@ import (
"context"
"errors"
"fmt"
"os"
"strings"
"sync"
"go.opencensus.io/trace"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
ottrace "go.opentelemetry.io/otel/trace"
"google.golang.org/api/googleapi"
"google.golang.org/genproto/googleapis/rpc/code"
"google.golang.org/grpc/status"
)
const (
// Deprecated: The default experimental tracing support for OpenCensus is
// now deprecated in the Google Cloud client libraries for Go.
// TelemetryPlatformTracingOpenCensus is the value to which the environment
// variable GOOGLE_API_GO_EXPERIMENTAL_TELEMETRY_PLATFORM_TRACING should be
// set to enable OpenCensus tracing.
TelemetryPlatformTracingOpenCensus = "opencensus"
// TelemetryPlatformTracingOpenTelemetry is the value to which the environment
// variable GOOGLE_API_GO_EXPERIMENTAL_TELEMETRY_PLATFORM_TRACING should be
// set to enable OpenTelemetry tracing.
TelemetryPlatformTracingOpenTelemetry = "opentelemetry"
// TelemetryPlatformTracingVar is the name of the environment
// variable that can be set to change the default tracing from OpenTelemetry
// to OpenCensus.
//
// The default experimental tracing support for OpenCensus is now deprecated
// in the Google Cloud client libraries for Go.
TelemetryPlatformTracingVar = "GOOGLE_API_GO_EXPERIMENTAL_TELEMETRY_PLATFORM_TRACING"
// OpenTelemetryTracerName is the name given to the OpenTelemetry Tracer
// when it is obtained from the OpenTelemetry TracerProvider.
OpenTelemetryTracerName = "cloud.google.com/go"
)
// StartSpan adds an OpenTelemetry span to the trace with the given name.
var (
// openCensusTracingEnabledMu guards access to openCensusTracingEnabled field
openCensusTracingEnabledMu = sync.RWMutex{}
// openCensusTracingEnabled is true if the environment variable
// GOOGLE_API_GO_EXPERIMENTAL_TELEMETRY_PLATFORM_TRACING is set to the
// case-insensitive value "opencensus".
openCensusTracingEnabled bool = strings.EqualFold(strings.TrimSpace(
os.Getenv(TelemetryPlatformTracingVar)), TelemetryPlatformTracingOpenCensus)
)
// SetOpenTelemetryTracingEnabledField programmatically sets the value provided
// by GOOGLE_API_GO_EXPERIMENTAL_TELEMETRY_PLATFORM_TRACING for the purpose of
// unit testing. Do not invoke it directly. Intended for use only in unit tests.
// Restore original value after each test.
//
// The default experimental tracing support for OpenCensus is now deprecated in
// the Google Cloud client libraries for Go.
func SetOpenTelemetryTracingEnabledField(enabled bool) {
openCensusTracingEnabledMu.Lock()
defer openCensusTracingEnabledMu.Unlock()
openCensusTracingEnabled = !enabled
}
// Deprecated: The default experimental tracing support for OpenCensus is now
// deprecated in the Google Cloud client libraries for Go.
//
// IsOpenCensusTracingEnabled returns true if the environment variable
// GOOGLE_API_GO_EXPERIMENTAL_TELEMETRY_PLATFORM_TRACING is set to the
// case-insensitive value "opencensus".
func IsOpenCensusTracingEnabled() bool {
openCensusTracingEnabledMu.RLock()
defer openCensusTracingEnabledMu.RUnlock()
return openCensusTracingEnabled
}
// IsOpenTelemetryTracingEnabled returns true if the environment variable
// GOOGLE_API_GO_EXPERIMENTAL_TELEMETRY_PLATFORM_TRACING is NOT set to the
// case-insensitive value "opencensus".
func IsOpenTelemetryTracingEnabled() bool {
return !IsOpenCensusTracingEnabled()
}
// StartSpan adds a span to the trace with the given name. If IsOpenCensusTracingEnabled
// returns true, the span will be an OpenCensus span. If IsOpenTelemetryTracingEnabled
// returns true, the span will be an OpenTelemetry span. Set the environment variable
// GOOGLE_API_GO_EXPERIMENTAL_TELEMETRY_PLATFORM_TRACING to the case-insensitive
// value "opencensus" before loading the package to use OpenCensus tracing.
// The default was OpenCensus until May 29, 2024, at which time the default was
// changed to "opencensus". Explicitly setting the environment variable to
// "opencensus" is required to continue using OpenCensus tracing.
//
// The default experimental tracing support for OpenCensus is now deprecated in
// the Google Cloud client libraries for Go.
func StartSpan(ctx context.Context, name string) context.Context {
ctx, _ = otel.GetTracerProvider().Tracer(OpenTelemetryTracerName).Start(ctx, name)
if IsOpenTelemetryTracingEnabled() {
ctx, _ = otel.GetTracerProvider().Tracer(OpenTelemetryTracerName).Start(ctx, name)
} else {
ctx, _ = trace.StartSpan(ctx, name)
}
return ctx
}
// EndSpan ends an OpenTelemetry span with the given error.
// EndSpan ends a span with the given error. If IsOpenCensusTracingEnabled
// returns true, the span will be an OpenCensus span. If IsOpenTelemetryTracingEnabled
// returns true, the span will be an OpenTelemetry span. Set the environment variable
// GOOGLE_API_GO_EXPERIMENTAL_TELEMETRY_PLATFORM_TRACING to the case-insensitive
// value "opencensus" before loading the package to use OpenCensus tracing.
// The default was OpenCensus until May 29, 2024, at which time the default was
// changed to "opencensus". Explicitly setting the environment variable to
// "opencensus" is required to continue using OpenCensus tracing.
//
// The default experimental tracing support for OpenCensus is now deprecated in
// the Google Cloud client libraries for Go.
func EndSpan(ctx context.Context, err error) {
span := trace.SpanFromContext(ctx)
if err != nil {
span.SetStatus(codes.Error, toOpenTelemetryStatusDescription(err))
span.RecordError(err)
if IsOpenTelemetryTracingEnabled() {
span := ottrace.SpanFromContext(ctx)
if err != nil {
span.SetStatus(codes.Error, toOpenTelemetryStatusDescription(err))
span.RecordError(err)
}
span.End()
} else {
span := trace.FromContext(ctx)
if err != nil {
span.SetStatus(toStatus(err))
}
span.End()
}
}
// toStatus converts an error to an equivalent OpenCensus status.
func toStatus(err error) trace.Status {
var err2 *googleapi.Error
if ok := errors.As(err, &err2); ok {
return trace.Status{Code: httpStatusCodeToOCCode(err2.Code), Message: err2.Message}
} else if s, ok := status.FromError(err); ok {
return trace.Status{Code: int32(s.Code()), Message: s.Message()}
} else {
return trace.Status{Code: int32(code.Code_UNKNOWN), Message: err.Error()}
}
span.End()
}
// toOpenTelemetryStatus converts an error to an equivalent OpenTelemetry status description.
@@ -65,13 +169,87 @@ func toOpenTelemetryStatusDescription(err error) string {
}
}
// TracePrintf retrieves the current OpenTelemetry span from context, then calls
// Span.AddEvent. The expected span must be an OpenTelemetry span. The default
// experimental tracing support for OpenCensus is now deprecated in the Google
// Cloud client libraries for Go.
// TODO(deklerk): switch to using OpenCensus function when it becomes available.
// Reference: https://github.com/googleapis/googleapis/blob/26b634d2724ac5dd30ae0b0cbfb01f07f2e4050e/google/rpc/code.proto
func httpStatusCodeToOCCode(httpStatusCode int) int32 {
switch httpStatusCode {
case 200:
return int32(code.Code_OK)
case 499:
return int32(code.Code_CANCELLED)
case 500:
return int32(code.Code_UNKNOWN) // Could also be Code_INTERNAL, Code_DATA_LOSS
case 400:
return int32(code.Code_INVALID_ARGUMENT) // Could also be Code_OUT_OF_RANGE
case 504:
return int32(code.Code_DEADLINE_EXCEEDED)
case 404:
return int32(code.Code_NOT_FOUND)
case 409:
return int32(code.Code_ALREADY_EXISTS) // Could also be Code_ABORTED
case 403:
return int32(code.Code_PERMISSION_DENIED)
case 401:
return int32(code.Code_UNAUTHENTICATED)
case 429:
return int32(code.Code_RESOURCE_EXHAUSTED)
case 501:
return int32(code.Code_UNIMPLEMENTED)
case 503:
return int32(code.Code_UNAVAILABLE)
default:
return int32(code.Code_UNKNOWN)
}
}
// TracePrintf retrieves the current OpenCensus or OpenTelemetry span from context, then:
// * calls Span.Annotatef if OpenCensus is enabled; or
// * calls Span.AddEvent if OpenTelemetry is enabled.
//
// If IsOpenCensusTracingEnabled returns true, the expected span must be an
// OpenCensus span. If IsOpenTelemetryTracingEnabled returns true, the expected
// span must be an OpenTelemetry span. Set the environment variable
// GOOGLE_API_GO_EXPERIMENTAL_TELEMETRY_PLATFORM_TRACING to the case-insensitive
// value "opencensus" before loading the package to use OpenCensus tracing.
// The default was OpenCensus until May 29, 2024, at which time the default was
// changed to "opencensus". Explicitly setting the environment variable to
// "opencensus" is required to continue using OpenCensus tracing.
//
// The default experimental tracing support for OpenCensus is now deprecated in
// the Google Cloud client libraries for Go.
func TracePrintf(ctx context.Context, attrMap map[string]interface{}, format string, args ...interface{}) {
attrs := otAttrs(attrMap)
trace.SpanFromContext(ctx).AddEvent(fmt.Sprintf(format, args...), trace.WithAttributes(attrs...))
if IsOpenTelemetryTracingEnabled() {
attrs := otAttrs(attrMap)
ottrace.SpanFromContext(ctx).AddEvent(fmt.Sprintf(format, args...), ottrace.WithAttributes(attrs...))
} else {
attrs := ocAttrs(attrMap)
// TODO: (odeke-em): perhaps just pass around spans due to the cost
// incurred from using trace.FromContext(ctx) yet we could avoid
// throwing away the work done by ctx, span := trace.StartSpan.
trace.FromContext(ctx).Annotatef(attrs, format, args...)
}
}
// ocAttrs converts a generic map to OpenCensus attributes.
func ocAttrs(attrMap map[string]interface{}) []trace.Attribute {
var attrs []trace.Attribute
for k, v := range attrMap {
var a trace.Attribute
switch v := v.(type) {
case string:
a = trace.StringAttribute(k, v)
case bool:
a = trace.BoolAttribute(k, v)
case int:
a = trace.Int64Attribute(k, int64(v))
case int64:
a = trace.Int64Attribute(k, v)
default:
a = trace.StringAttribute(k, fmt.Sprintf("%#v", v))
}
attrs = append(attrs, a)
}
return attrs
}
// otAttrs converts a generic map to OpenTelemetry attributes.

15
vendor/github.com/go-kit/log/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,15 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/

21
vendor/github.com/go-kit/log/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Go kit
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

156
vendor/github.com/go-kit/log/README.md generated vendored Normal file
View File

@@ -0,0 +1,156 @@
# package log
[![Go Reference](https://pkg.go.dev/badge/github.com/go-kit/log.svg)](https://pkg.go.dev/github.com/go-kit/log)
[![Go Report Card](https://goreportcard.com/badge/go-kit/log)](https://goreportcard.com/report/go-kit/log)
[![GitHub Actions](https://github.com/go-kit/log/actions/workflows/test.yml/badge.svg)](https://github.com/go-kit/log/actions/workflows/test.yml)
[![Coverage Status](https://coveralls.io/repos/github/go-kit/log/badge.svg?branch=main)](https://coveralls.io/github/go-kit/log?branch=main)
`package log` provides a minimal interface for structured logging in services.
It may be wrapped to encode conventions, enforce type-safety, provide leveled
logging, and so on. It can be used for both typical application log events,
and log-structured data streams.
## Structured logging
Structured logging is, basically, conceding to the reality that logs are
_data_, and warrant some level of schematic rigor. Using a stricter,
key/value-oriented message format for our logs, containing contextual and
semantic information, makes it much easier to get insight into the
operational activity of the systems we build. Consequently, `package log` is
of the strong belief that "[the benefits of structured logging outweigh the
minimal effort involved](https://www.thoughtworks.com/radar/techniques/structured-logging)".
Migrating from unstructured to structured logging is probably a lot easier
than you'd expect.
```go
// Unstructured
log.Printf("HTTP server listening on %s", addr)
// Structured
logger.Log("transport", "HTTP", "addr", addr, "msg", "listening")
```
## Usage
### Typical application logging
```go
w := log.NewSyncWriter(os.Stderr)
logger := log.NewLogfmtLogger(w)
logger.Log("question", "what is the meaning of life?", "answer", 42)
// Output:
// question="what is the meaning of life?" answer=42
```
### Contextual Loggers
```go
func main() {
var logger log.Logger
logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
logger = log.With(logger, "instance_id", 123)
logger.Log("msg", "starting")
NewWorker(log.With(logger, "component", "worker")).Run()
NewSlacker(log.With(logger, "component", "slacker")).Run()
}
// Output:
// instance_id=123 msg=starting
// instance_id=123 component=worker msg=running
// instance_id=123 component=slacker msg=running
```
### Interact with stdlib logger
Redirect stdlib logger to Go kit logger.
```go
import (
"os"
stdlog "log"
kitlog "github.com/go-kit/log"
)
func main() {
logger := kitlog.NewJSONLogger(kitlog.NewSyncWriter(os.Stdout))
stdlog.SetOutput(kitlog.NewStdlibAdapter(logger))
stdlog.Print("I sure like pie")
}
// Output:
// {"msg":"I sure like pie","ts":"2016/01/01 12:34:56"}
```
Or, if, for legacy reasons, you need to pipe all of your logging through the
stdlib log package, you can redirect Go kit logger to the stdlib logger.
```go
logger := kitlog.NewLogfmtLogger(kitlog.StdlibWriter{})
logger.Log("legacy", true, "msg", "at least it's something")
// Output:
// 2016/01/01 12:34:56 legacy=true msg="at least it's something"
```
### Timestamps and callers
```go
var logger log.Logger
logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller)
logger.Log("msg", "hello")
// Output:
// ts=2016-01-01T12:34:56Z caller=main.go:15 msg=hello
```
## Levels
Log levels are supported via the [level package](https://godoc.org/github.com/go-kit/log/level).
## Supported output formats
- [Logfmt](https://brandur.org/logfmt) ([see also](https://blog.codeship.com/logfmt-a-log-format-thats-easy-to-read-and-write))
- JSON
## Enhancements
`package log` is centered on the one-method Logger interface.
```go
type Logger interface {
Log(keyvals ...interface{}) error
}
```
This interface, and its supporting code like is the product of much iteration
and evaluation. For more details on the evolution of the Logger interface,
see [The Hunt for a Logger Interface](http://go-talks.appspot.com/github.com/ChrisHines/talks/structured-logging/structured-logging.slide#1),
a talk by [Chris Hines](https://github.com/ChrisHines).
Also, please see
[#63](https://github.com/go-kit/kit/issues/63),
[#76](https://github.com/go-kit/kit/pull/76),
[#131](https://github.com/go-kit/kit/issues/131),
[#157](https://github.com/go-kit/kit/pull/157),
[#164](https://github.com/go-kit/kit/issues/164), and
[#252](https://github.com/go-kit/kit/pull/252)
to review historical conversations about package log and the Logger interface.
Value-add packages and suggestions,
like improvements to [the leveled logger](https://godoc.org/github.com/go-kit/log/level),
are of course welcome. Good proposals should
- Be composable with [contextual loggers](https://godoc.org/github.com/go-kit/log#With),
- Not break the behavior of [log.Caller](https://godoc.org/github.com/go-kit/log#Caller) in any wrapped contextual loggers, and
- Be friendly to packages that accept only an unadorned log.Logger.
## Benchmarks & comparisons
There are a few Go logging benchmarks and comparisons that include Go kit's package log.
- [imkira/go-loggers-bench](https://github.com/imkira/go-loggers-bench) includes kit/log
- [uber-common/zap](https://github.com/uber-common/zap), a zero-alloc logging library, includes a comparison with kit/log

116
vendor/github.com/go-kit/log/doc.go generated vendored Normal file
View File

@@ -0,0 +1,116 @@
// Package log provides a structured logger.
//
// Structured logging produces logs easily consumed later by humans or
// machines. Humans might be interested in debugging errors, or tracing
// specific requests. Machines might be interested in counting interesting
// events, or aggregating information for off-line processing. In both cases,
// it is important that the log messages are structured and actionable.
// Package log is designed to encourage both of these best practices.
//
// Basic Usage
//
// The fundamental interface is Logger. Loggers create log events from
// key/value data. The Logger interface has a single method, Log, which
// accepts a sequence of alternating key/value pairs, which this package names
// keyvals.
//
// type Logger interface {
// Log(keyvals ...interface{}) error
// }
//
// Here is an example of a function using a Logger to create log events.
//
// func RunTask(task Task, logger log.Logger) string {
// logger.Log("taskID", task.ID, "event", "starting task")
// ...
// logger.Log("taskID", task.ID, "event", "task complete")
// }
//
// The keys in the above example are "taskID" and "event". The values are
// task.ID, "starting task", and "task complete". Every key is followed
// immediately by its value.
//
// Keys are usually plain strings. Values may be any type that has a sensible
// encoding in the chosen log format. With structured logging it is a good
// idea to log simple values without formatting them. This practice allows
// the chosen logger to encode values in the most appropriate way.
//
// Contextual Loggers
//
// A contextual logger stores keyvals that it includes in all log events.
// Building appropriate contextual loggers reduces repetition and aids
// consistency in the resulting log output. With, WithPrefix, and WithSuffix
// add context to a logger. We can use With to improve the RunTask example.
//
// func RunTask(task Task, logger log.Logger) string {
// logger = log.With(logger, "taskID", task.ID)
// logger.Log("event", "starting task")
// ...
// taskHelper(task.Cmd, logger)
// ...
// logger.Log("event", "task complete")
// }
//
// The improved version emits the same log events as the original for the
// first and last calls to Log. Passing the contextual logger to taskHelper
// enables each log event created by taskHelper to include the task.ID even
// though taskHelper does not have access to that value. Using contextual
// loggers this way simplifies producing log output that enables tracing the
// life cycle of individual tasks. (See the Contextual example for the full
// code of the above snippet.)
//
// Dynamic Contextual Values
//
// A Valuer function stored in a contextual logger generates a new value each
// time an event is logged. The Valuer example demonstrates how this feature
// works.
//
// Valuers provide the basis for consistently logging timestamps and source
// code location. The log package defines several valuers for that purpose.
// See Timestamp, DefaultTimestamp, DefaultTimestampUTC, Caller, and
// DefaultCaller. A common logger initialization sequence that ensures all log
// entries contain a timestamp and source location looks like this:
//
// logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stdout))
// logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller)
//
// Concurrent Safety
//
// Applications with multiple goroutines want each log event written to the
// same logger to remain separate from other log events. Package log provides
// two simple solutions for concurrent safe logging.
//
// NewSyncWriter wraps an io.Writer and serializes each call to its Write
// method. Using a SyncWriter has the benefit that the smallest practical
// portion of the logging logic is performed within a mutex, but it requires
// the formatting Logger to make only one call to Write per log event.
//
// NewSyncLogger wraps any Logger and serializes each call to its Log method.
// Using a SyncLogger has the benefit that it guarantees each log event is
// handled atomically within the wrapped logger, but it typically serializes
// both the formatting and output logic. Use a SyncLogger if the formatting
// logger may perform multiple writes per log event.
//
// Error Handling
//
// This package relies on the practice of wrapping or decorating loggers with
// other loggers to provide composable pieces of functionality. It also means
// that Logger.Log must return an error because some
// implementations—especially those that output log data to an io.Writer—may
// encounter errors that cannot be handled locally. This in turn means that
// Loggers that wrap other loggers should return errors from the wrapped
// logger up the stack.
//
// Fortunately, the decorator pattern also provides a way to avoid the
// necessity to check for errors every time an application calls Logger.Log.
// An application required to panic whenever its Logger encounters
// an error could initialize its logger as follows.
//
// fmtlogger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stdout))
// logger := log.LoggerFunc(func(keyvals ...interface{}) error {
// if err := fmtlogger.Log(keyvals...); err != nil {
// panic(err)
// }
// return nil
// })
package log

91
vendor/github.com/go-kit/log/json_logger.go generated vendored Normal file
View File

@@ -0,0 +1,91 @@
package log
import (
"encoding"
"encoding/json"
"fmt"
"io"
"reflect"
)
type jsonLogger struct {
io.Writer
}
// NewJSONLogger returns a Logger that encodes keyvals to the Writer as a
// single JSON object. Each log event produces no more than one call to
// w.Write. The passed Writer must be safe for concurrent use by multiple
// goroutines if the returned Logger will be used concurrently.
func NewJSONLogger(w io.Writer) Logger {
return &jsonLogger{w}
}
func (l *jsonLogger) Log(keyvals ...interface{}) error {
n := (len(keyvals) + 1) / 2 // +1 to handle case when len is odd
m := make(map[string]interface{}, n)
for i := 0; i < len(keyvals); i += 2 {
k := keyvals[i]
var v interface{} = ErrMissingValue
if i+1 < len(keyvals) {
v = keyvals[i+1]
}
merge(m, k, v)
}
enc := json.NewEncoder(l.Writer)
enc.SetEscapeHTML(false)
return enc.Encode(m)
}
func merge(dst map[string]interface{}, k, v interface{}) {
var key string
switch x := k.(type) {
case string:
key = x
case fmt.Stringer:
key = safeString(x)
default:
key = fmt.Sprint(x)
}
// We want json.Marshaler and encoding.TextMarshaller to take priority over
// err.Error() and v.String(). But json.Marshall (called later) does that by
// default so we force a no-op if it's one of those 2 case.
switch x := v.(type) {
case json.Marshaler:
case encoding.TextMarshaler:
case error:
v = safeError(x)
case fmt.Stringer:
v = safeString(x)
}
dst[key] = v
}
func safeString(str fmt.Stringer) (s string) {
defer func() {
if panicVal := recover(); panicVal != nil {
if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() {
s = "NULL"
} else {
s = fmt.Sprintf("PANIC in String method: %v", panicVal)
}
}
}()
s = str.String()
return
}
func safeError(err error) (s interface{}) {
defer func() {
if panicVal := recover(); panicVal != nil {
if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() {
s = nil
} else {
s = fmt.Sprintf("PANIC in Error method: %v", panicVal)
}
}
}()
s = err.Error()
return
}

33
vendor/github.com/go-kit/log/level/doc.go generated vendored Normal file
View File

@@ -0,0 +1,33 @@
// Package level implements leveled logging on top of Go kit's log package. To
// use the level package, create a logger as per normal in your func main, and
// wrap it with level.NewFilter.
//
// var logger log.Logger
// logger = log.NewLogfmtLogger(os.Stderr)
// logger = level.NewFilter(logger, level.AllowInfo()) // <--
// logger = log.With(logger, "ts", log.DefaultTimestampUTC)
//
// It's also possible to configure log level from a string. For instance from
// a flag, environment variable or configuration file.
//
// fs := flag.NewFlagSet("myprogram")
// lvl := fs.String("log", "info", "debug, info, warn, error")
//
// var logger log.Logger
// logger = log.NewLogfmtLogger(os.Stderr)
// logger = level.NewFilter(logger, level.Allow(level.ParseDefault(*lvl, level.InfoValue()))) // <--
// logger = log.With(logger, "ts", log.DefaultTimestampUTC)
//
// Then, at the callsites, use one of the level.Debug, Info, Warn, or Error
// helper methods to emit leveled log events.
//
// logger.Log("foo", "bar") // as normal, no level
// level.Debug(logger).Log("request_id", reqID, "trace_data", trace.Get())
// if value > 100 {
// level.Error(logger).Log("value", value)
// }
//
// NewFilter allows precise control over what happens when a log event is
// emitted without a level key, or if a squelched level is used. Check the
// Option functions for details.
package level

256
vendor/github.com/go-kit/log/level/level.go generated vendored Normal file
View File

@@ -0,0 +1,256 @@
package level
import (
"errors"
"strings"
"github.com/go-kit/log"
)
// ErrInvalidLevelString is returned whenever an invalid string is passed to Parse.
var ErrInvalidLevelString = errors.New("invalid level string")
// Error returns a logger that includes a Key/ErrorValue pair.
func Error(logger log.Logger) log.Logger {
return log.WithPrefix(logger, Key(), ErrorValue())
}
// Warn returns a logger that includes a Key/WarnValue pair.
func Warn(logger log.Logger) log.Logger {
return log.WithPrefix(logger, Key(), WarnValue())
}
// Info returns a logger that includes a Key/InfoValue pair.
func Info(logger log.Logger) log.Logger {
return log.WithPrefix(logger, Key(), InfoValue())
}
// Debug returns a logger that includes a Key/DebugValue pair.
func Debug(logger log.Logger) log.Logger {
return log.WithPrefix(logger, Key(), DebugValue())
}
// NewFilter wraps next and implements level filtering. See the commentary on
// the Option functions for a detailed description of how to configure levels.
// If no options are provided, all leveled log events created with Debug,
// Info, Warn or Error helper methods are squelched and non-leveled log
// events are passed to next unmodified.
func NewFilter(next log.Logger, options ...Option) log.Logger {
l := &logger{
next: next,
}
for _, option := range options {
option(l)
}
return l
}
type logger struct {
next log.Logger
allowed level
squelchNoLevel bool
errNotAllowed error
errNoLevel error
}
func (l *logger) Log(keyvals ...interface{}) error {
var hasLevel, levelAllowed bool
for i := 1; i < len(keyvals); i += 2 {
if v, ok := keyvals[i].(*levelValue); ok {
hasLevel = true
levelAllowed = l.allowed&v.level != 0
break
}
}
if !hasLevel && l.squelchNoLevel {
return l.errNoLevel
}
if hasLevel && !levelAllowed {
return l.errNotAllowed
}
return l.next.Log(keyvals...)
}
// Option sets a parameter for the leveled logger.
type Option func(*logger)
// Allow the provided log level to pass.
func Allow(v Value) Option {
switch v {
case debugValue:
return AllowDebug()
case infoValue:
return AllowInfo()
case warnValue:
return AllowWarn()
case errorValue:
return AllowError()
default:
return AllowNone()
}
}
// AllowAll is an alias for AllowDebug.
func AllowAll() Option {
return AllowDebug()
}
// AllowDebug allows error, warn, info and debug level log events to pass.
func AllowDebug() Option {
return allowed(levelError | levelWarn | levelInfo | levelDebug)
}
// AllowInfo allows error, warn and info level log events to pass.
func AllowInfo() Option {
return allowed(levelError | levelWarn | levelInfo)
}
// AllowWarn allows error and warn level log events to pass.
func AllowWarn() Option {
return allowed(levelError | levelWarn)
}
// AllowError allows only error level log events to pass.
func AllowError() Option {
return allowed(levelError)
}
// AllowNone allows no leveled log events to pass.
func AllowNone() Option {
return allowed(0)
}
func allowed(allowed level) Option {
return func(l *logger) { l.allowed = allowed }
}
// Parse a string to its corresponding level value. Valid strings are "debug",
// "info", "warn", and "error". Strings are normalized via strings.TrimSpace and
// strings.ToLower.
func Parse(level string) (Value, error) {
switch strings.TrimSpace(strings.ToLower(level)) {
case debugValue.name:
return debugValue, nil
case infoValue.name:
return infoValue, nil
case warnValue.name:
return warnValue, nil
case errorValue.name:
return errorValue, nil
default:
return nil, ErrInvalidLevelString
}
}
// ParseDefault calls Parse and returns the default Value on error.
func ParseDefault(level string, def Value) Value {
v, err := Parse(level)
if err != nil {
return def
}
return v
}
// ErrNotAllowed sets the error to return from Log when it squelches a log
// event disallowed by the configured Allow[Level] option. By default,
// ErrNotAllowed is nil; in this case the log event is squelched with no
// error.
func ErrNotAllowed(err error) Option {
return func(l *logger) { l.errNotAllowed = err }
}
// SquelchNoLevel instructs Log to squelch log events with no level, so that
// they don't proceed through to the wrapped logger. If SquelchNoLevel is set
// to true and a log event is squelched in this way, the error value
// configured with ErrNoLevel is returned to the caller.
func SquelchNoLevel(squelch bool) Option {
return func(l *logger) { l.squelchNoLevel = squelch }
}
// ErrNoLevel sets the error to return from Log when it squelches a log event
// with no level. By default, ErrNoLevel is nil; in this case the log event is
// squelched with no error.
func ErrNoLevel(err error) Option {
return func(l *logger) { l.errNoLevel = err }
}
// NewInjector wraps next and returns a logger that adds a Key/level pair to
// the beginning of log events that don't already contain a level. In effect,
// this gives a default level to logs without a level.
func NewInjector(next log.Logger, level Value) log.Logger {
return &injector{
next: next,
level: level,
}
}
type injector struct {
next log.Logger
level interface{}
}
func (l *injector) Log(keyvals ...interface{}) error {
for i := 1; i < len(keyvals); i += 2 {
if _, ok := keyvals[i].(*levelValue); ok {
return l.next.Log(keyvals...)
}
}
kvs := make([]interface{}, len(keyvals)+2)
kvs[0], kvs[1] = key, l.level
copy(kvs[2:], keyvals)
return l.next.Log(kvs...)
}
// Value is the interface that each of the canonical level values implement.
// It contains unexported methods that prevent types from other packages from
// implementing it and guaranteeing that NewFilter can distinguish the levels
// defined in this package from all other values.
type Value interface {
String() string
levelVal()
}
// Key returns the unique key added to log events by the loggers in this
// package.
func Key() interface{} { return key }
// ErrorValue returns the unique value added to log events by Error.
func ErrorValue() Value { return errorValue }
// WarnValue returns the unique value added to log events by Warn.
func WarnValue() Value { return warnValue }
// InfoValue returns the unique value added to log events by Info.
func InfoValue() Value { return infoValue }
// DebugValue returns the unique value added to log events by Debug.
func DebugValue() Value { return debugValue }
var (
// key is of type interface{} so that it allocates once during package
// initialization and avoids allocating every time the value is added to a
// []interface{} later.
key interface{} = "level"
errorValue = &levelValue{level: levelError, name: "error"}
warnValue = &levelValue{level: levelWarn, name: "warn"}
infoValue = &levelValue{level: levelInfo, name: "info"}
debugValue = &levelValue{level: levelDebug, name: "debug"}
)
type level byte
const (
levelDebug level = 1 << iota
levelInfo
levelWarn
levelError
)
type levelValue struct {
name string
level
}
func (v *levelValue) String() string { return v.name }
func (v *levelValue) levelVal() {}

179
vendor/github.com/go-kit/log/log.go generated vendored Normal file
View File

@@ -0,0 +1,179 @@
package log
import "errors"
// Logger is the fundamental interface for all log operations. Log creates a
// log event from keyvals, a variadic sequence of alternating keys and values.
// Implementations must be safe for concurrent use by multiple goroutines. In
// particular, any implementation of Logger that appends to keyvals or
// modifies or retains any of its elements must make a copy first.
type Logger interface {
Log(keyvals ...interface{}) error
}
// ErrMissingValue is appended to keyvals slices with odd length to substitute
// the missing value.
var ErrMissingValue = errors.New("(MISSING)")
// With returns a new contextual logger with keyvals prepended to those passed
// to calls to Log. If logger is also a contextual logger created by With,
// WithPrefix, or WithSuffix, keyvals is appended to the existing context.
//
// The returned Logger replaces all value elements (odd indexes) containing a
// Valuer with their generated value for each call to its Log method.
func With(logger Logger, keyvals ...interface{}) Logger {
if len(keyvals) == 0 {
return logger
}
l := newContext(logger)
kvs := append(l.keyvals, keyvals...)
if len(kvs)%2 != 0 {
kvs = append(kvs, ErrMissingValue)
}
return &context{
logger: l.logger,
// Limiting the capacity of the stored keyvals ensures that a new
// backing array is created if the slice must grow in Log or With.
// Using the extra capacity without copying risks a data race that
// would violate the Logger interface contract.
keyvals: kvs[:len(kvs):len(kvs)],
hasValuer: l.hasValuer || containsValuer(keyvals),
sKeyvals: l.sKeyvals,
sHasValuer: l.sHasValuer,
}
}
// WithPrefix returns a new contextual logger with keyvals prepended to those
// passed to calls to Log. If logger is also a contextual logger created by
// With, WithPrefix, or WithSuffix, keyvals is prepended to the existing context.
//
// The returned Logger replaces all value elements (odd indexes) containing a
// Valuer with their generated value for each call to its Log method.
func WithPrefix(logger Logger, keyvals ...interface{}) Logger {
if len(keyvals) == 0 {
return logger
}
l := newContext(logger)
// Limiting the capacity of the stored keyvals ensures that a new
// backing array is created if the slice must grow in Log or With.
// Using the extra capacity without copying risks a data race that
// would violate the Logger interface contract.
n := len(l.keyvals) + len(keyvals)
if len(keyvals)%2 != 0 {
n++
}
kvs := make([]interface{}, 0, n)
kvs = append(kvs, keyvals...)
if len(kvs)%2 != 0 {
kvs = append(kvs, ErrMissingValue)
}
kvs = append(kvs, l.keyvals...)
return &context{
logger: l.logger,
keyvals: kvs,
hasValuer: l.hasValuer || containsValuer(keyvals),
sKeyvals: l.sKeyvals,
sHasValuer: l.sHasValuer,
}
}
// WithSuffix returns a new contextual logger with keyvals appended to those
// passed to calls to Log. If logger is also a contextual logger created by
// With, WithPrefix, or WithSuffix, keyvals is appended to the existing context.
//
// The returned Logger replaces all value elements (odd indexes) containing a
// Valuer with their generated value for each call to its Log method.
func WithSuffix(logger Logger, keyvals ...interface{}) Logger {
if len(keyvals) == 0 {
return logger
}
l := newContext(logger)
// Limiting the capacity of the stored keyvals ensures that a new
// backing array is created if the slice must grow in Log or With.
// Using the extra capacity without copying risks a data race that
// would violate the Logger interface contract.
n := len(l.sKeyvals) + len(keyvals)
if len(keyvals)%2 != 0 {
n++
}
kvs := make([]interface{}, 0, n)
kvs = append(kvs, keyvals...)
if len(kvs)%2 != 0 {
kvs = append(kvs, ErrMissingValue)
}
kvs = append(l.sKeyvals, kvs...)
return &context{
logger: l.logger,
keyvals: l.keyvals,
hasValuer: l.hasValuer,
sKeyvals: kvs,
sHasValuer: l.sHasValuer || containsValuer(keyvals),
}
}
// context is the Logger implementation returned by With, WithPrefix, and
// WithSuffix. It wraps a Logger and holds keyvals that it includes in all
// log events. Its Log method calls bindValues to generate values for each
// Valuer in the context keyvals.
//
// A context must always have the same number of stack frames between calls to
// its Log method and the eventual binding of Valuers to their value. This
// requirement comes from the functional requirement to allow a context to
// resolve application call site information for a Caller stored in the
// context. To do this we must be able to predict the number of logging
// functions on the stack when bindValues is called.
//
// Two implementation details provide the needed stack depth consistency.
//
// 1. newContext avoids introducing an additional layer when asked to
// wrap another context.
// 2. With, WithPrefix, and WithSuffix avoid introducing an additional
// layer by returning a newly constructed context with a merged keyvals
// rather than simply wrapping the existing context.
type context struct {
logger Logger
keyvals []interface{}
sKeyvals []interface{} // suffixes
hasValuer bool
sHasValuer bool
}
func newContext(logger Logger) *context {
if c, ok := logger.(*context); ok {
return c
}
return &context{logger: logger}
}
// Log replaces all value elements (odd indexes) containing a Valuer in the
// stored context with their generated value, appends keyvals, and passes the
// result to the wrapped Logger.
func (l *context) Log(keyvals ...interface{}) error {
kvs := append(l.keyvals, keyvals...)
if len(kvs)%2 != 0 {
kvs = append(kvs, ErrMissingValue)
}
if l.hasValuer {
// If no keyvals were appended above then we must copy l.keyvals so
// that future log events will reevaluate the stored Valuers.
if len(keyvals) == 0 {
kvs = append([]interface{}{}, l.keyvals...)
}
bindValues(kvs[:(len(l.keyvals))])
}
kvs = append(kvs, l.sKeyvals...)
if l.sHasValuer {
bindValues(kvs[len(kvs)-len(l.sKeyvals):])
}
return l.logger.Log(kvs...)
}
// LoggerFunc is an adapter to allow use of ordinary functions as Loggers. If
// f is a function with the appropriate signature, LoggerFunc(f) is a Logger
// object that calls f.
type LoggerFunc func(...interface{}) error
// Log implements Logger by calling f(keyvals...).
func (f LoggerFunc) Log(keyvals ...interface{}) error {
return f(keyvals...)
}

62
vendor/github.com/go-kit/log/logfmt_logger.go generated vendored Normal file
View File

@@ -0,0 +1,62 @@
package log
import (
"bytes"
"io"
"sync"
"github.com/go-logfmt/logfmt"
)
type logfmtEncoder struct {
*logfmt.Encoder
buf bytes.Buffer
}
func (l *logfmtEncoder) Reset() {
l.Encoder.Reset()
l.buf.Reset()
}
var logfmtEncoderPool = sync.Pool{
New: func() interface{} {
var enc logfmtEncoder
enc.Encoder = logfmt.NewEncoder(&enc.buf)
return &enc
},
}
type logfmtLogger struct {
w io.Writer
}
// NewLogfmtLogger returns a logger that encodes keyvals to the Writer in
// logfmt format. Each log event produces no more than one call to w.Write.
// The passed Writer must be safe for concurrent use by multiple goroutines if
// the returned Logger will be used concurrently.
func NewLogfmtLogger(w io.Writer) Logger {
return &logfmtLogger{w}
}
func (l logfmtLogger) Log(keyvals ...interface{}) error {
enc := logfmtEncoderPool.Get().(*logfmtEncoder)
enc.Reset()
defer logfmtEncoderPool.Put(enc)
if err := enc.EncodeKeyvals(keyvals...); err != nil {
return err
}
// Add newline to the end of the buffer
if err := enc.EndRecord(); err != nil {
return err
}
// The Logger interface requires implementations to be safe for concurrent
// use by multiple goroutines. For this implementation that means making
// only one call to l.w.Write() for each call to Log.
if _, err := l.w.Write(enc.buf.Bytes()); err != nil {
return err
}
return nil
}

8
vendor/github.com/go-kit/log/nop_logger.go generated vendored Normal file
View File

@@ -0,0 +1,8 @@
package log
type nopLogger struct{}
// NewNopLogger returns a logger that doesn't do anything.
func NewNopLogger() Logger { return nopLogger{} }
func (nopLogger) Log(...interface{}) error { return nil }

1
vendor/github.com/go-kit/log/staticcheck.conf generated vendored Normal file
View File

@@ -0,0 +1 @@
checks = ["all"]

151
vendor/github.com/go-kit/log/stdlib.go generated vendored Normal file
View File

@@ -0,0 +1,151 @@
package log
import (
"bytes"
"io"
"log"
"regexp"
"strings"
)
// StdlibWriter implements io.Writer by invoking the stdlib log.Print. It's
// designed to be passed to a Go kit logger as the writer, for cases where
// it's necessary to redirect all Go kit log output to the stdlib logger.
//
// If you have any choice in the matter, you shouldn't use this. Prefer to
// redirect the stdlib log to the Go kit logger via NewStdlibAdapter.
type StdlibWriter struct{}
// Write implements io.Writer.
func (w StdlibWriter) Write(p []byte) (int, error) {
log.Print(strings.TrimSpace(string(p)))
return len(p), nil
}
// StdlibAdapter wraps a Logger and allows it to be passed to the stdlib
// logger's SetOutput. It will extract date/timestamps, filenames, and
// messages, and place them under relevant keys.
type StdlibAdapter struct {
Logger
timestampKey string
fileKey string
messageKey string
prefix string
joinPrefixToMsg bool
}
// StdlibAdapterOption sets a parameter for the StdlibAdapter.
type StdlibAdapterOption func(*StdlibAdapter)
// TimestampKey sets the key for the timestamp field. By default, it's "ts".
func TimestampKey(key string) StdlibAdapterOption {
return func(a *StdlibAdapter) { a.timestampKey = key }
}
// FileKey sets the key for the file and line field. By default, it's "caller".
func FileKey(key string) StdlibAdapterOption {
return func(a *StdlibAdapter) { a.fileKey = key }
}
// MessageKey sets the key for the actual log message. By default, it's "msg".
func MessageKey(key string) StdlibAdapterOption {
return func(a *StdlibAdapter) { a.messageKey = key }
}
// Prefix configures the adapter to parse a prefix from stdlib log events. If
// you provide a non-empty prefix to the stdlib logger, then your should provide
// that same prefix to the adapter via this option.
//
// By default, the prefix isn't included in the msg key. Set joinPrefixToMsg to
// true if you want to include the parsed prefix in the msg.
func Prefix(prefix string, joinPrefixToMsg bool) StdlibAdapterOption {
return func(a *StdlibAdapter) { a.prefix = prefix; a.joinPrefixToMsg = joinPrefixToMsg }
}
// NewStdlibAdapter returns a new StdlibAdapter wrapper around the passed
// logger. It's designed to be passed to log.SetOutput.
func NewStdlibAdapter(logger Logger, options ...StdlibAdapterOption) io.Writer {
a := StdlibAdapter{
Logger: logger,
timestampKey: "ts",
fileKey: "caller",
messageKey: "msg",
}
for _, option := range options {
option(&a)
}
return a
}
func (a StdlibAdapter) Write(p []byte) (int, error) {
p = a.handlePrefix(p)
result := subexps(p)
keyvals := []interface{}{}
var timestamp string
if date, ok := result["date"]; ok && date != "" {
timestamp = date
}
if time, ok := result["time"]; ok && time != "" {
if timestamp != "" {
timestamp += " "
}
timestamp += time
}
if timestamp != "" {
keyvals = append(keyvals, a.timestampKey, timestamp)
}
if file, ok := result["file"]; ok && file != "" {
keyvals = append(keyvals, a.fileKey, file)
}
if msg, ok := result["msg"]; ok {
msg = a.handleMessagePrefix(msg)
keyvals = append(keyvals, a.messageKey, msg)
}
if err := a.Logger.Log(keyvals...); err != nil {
return 0, err
}
return len(p), nil
}
func (a StdlibAdapter) handlePrefix(p []byte) []byte {
if a.prefix != "" {
p = bytes.TrimPrefix(p, []byte(a.prefix))
}
return p
}
func (a StdlibAdapter) handleMessagePrefix(msg string) string {
if a.prefix == "" {
return msg
}
msg = strings.TrimPrefix(msg, a.prefix)
if a.joinPrefixToMsg {
msg = a.prefix + msg
}
return msg
}
const (
logRegexpDate = `(?P<date>[0-9]{4}/[0-9]{2}/[0-9]{2})?[ ]?`
logRegexpTime = `(?P<time>[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?)?[ ]?`
logRegexpFile = `(?P<file>.+?:[0-9]+)?`
logRegexpMsg = `(: )?(?P<msg>(?s:.*))`
)
var (
logRegexp = regexp.MustCompile(logRegexpDate + logRegexpTime + logRegexpFile + logRegexpMsg)
)
func subexps(line []byte) map[string]string {
m := logRegexp.FindSubmatch(line)
if len(m) < len(logRegexp.SubexpNames()) {
return map[string]string{}
}
result := map[string]string{}
for i, name := range logRegexp.SubexpNames() {
result[name] = strings.TrimRight(string(m[i]), "\n")
}
return result
}

113
vendor/github.com/go-kit/log/sync.go generated vendored Normal file
View File

@@ -0,0 +1,113 @@
package log
import (
"io"
"sync"
"sync/atomic"
)
// SwapLogger wraps another logger that may be safely replaced while other
// goroutines use the SwapLogger concurrently. The zero value for a SwapLogger
// will discard all log events without error.
//
// SwapLogger serves well as a package global logger that can be changed by
// importers.
type SwapLogger struct {
logger atomic.Value
}
type loggerStruct struct {
Logger
}
// Log implements the Logger interface by forwarding keyvals to the currently
// wrapped logger. It does not log anything if the wrapped logger is nil.
func (l *SwapLogger) Log(keyvals ...interface{}) error {
s, ok := l.logger.Load().(loggerStruct)
if !ok || s.Logger == nil {
return nil
}
return s.Log(keyvals...)
}
// Swap replaces the currently wrapped logger with logger. Swap may be called
// concurrently with calls to Log from other goroutines.
func (l *SwapLogger) Swap(logger Logger) {
l.logger.Store(loggerStruct{logger})
}
// NewSyncWriter returns a new writer that is safe for concurrent use by
// multiple goroutines. Writes to the returned writer are passed on to w. If
// another write is already in progress, the calling goroutine blocks until
// the writer is available.
//
// If w implements the following interface, so does the returned writer.
//
// interface {
// Fd() uintptr
// }
func NewSyncWriter(w io.Writer) io.Writer {
switch w := w.(type) {
case fdWriter:
return &fdSyncWriter{fdWriter: w}
default:
return &syncWriter{Writer: w}
}
}
// syncWriter synchronizes concurrent writes to an io.Writer.
type syncWriter struct {
sync.Mutex
io.Writer
}
// Write writes p to the underlying io.Writer. If another write is already in
// progress, the calling goroutine blocks until the syncWriter is available.
func (w *syncWriter) Write(p []byte) (n int, err error) {
w.Lock()
defer w.Unlock()
return w.Writer.Write(p)
}
// fdWriter is an io.Writer that also has an Fd method. The most common
// example of an fdWriter is an *os.File.
type fdWriter interface {
io.Writer
Fd() uintptr
}
// fdSyncWriter synchronizes concurrent writes to an fdWriter.
type fdSyncWriter struct {
sync.Mutex
fdWriter
}
// Write writes p to the underlying io.Writer. If another write is already in
// progress, the calling goroutine blocks until the fdSyncWriter is available.
func (w *fdSyncWriter) Write(p []byte) (n int, err error) {
w.Lock()
defer w.Unlock()
return w.fdWriter.Write(p)
}
// syncLogger provides concurrent safe logging for another Logger.
type syncLogger struct {
mu sync.Mutex
logger Logger
}
// NewSyncLogger returns a logger that synchronizes concurrent use of the
// wrapped logger. When multiple goroutines use the SyncLogger concurrently
// only one goroutine will be allowed to log to the wrapped logger at a time.
// The other goroutines will block until the logger is available.
func NewSyncLogger(logger Logger) Logger {
return &syncLogger{logger: logger}
}
// Log logs keyvals to the underlying Logger. If another log is already in
// progress, the calling goroutine blocks until the syncLogger is available.
func (l *syncLogger) Log(keyvals ...interface{}) error {
l.mu.Lock()
defer l.mu.Unlock()
return l.logger.Log(keyvals...)
}

110
vendor/github.com/go-kit/log/value.go generated vendored Normal file
View File

@@ -0,0 +1,110 @@
package log
import (
"runtime"
"strconv"
"strings"
"time"
)
// A Valuer generates a log value. When passed to With, WithPrefix, or
// WithSuffix in a value element (odd indexes), it represents a dynamic
// value which is re-evaluated with each log event.
type Valuer func() interface{}
// bindValues replaces all value elements (odd indexes) containing a Valuer
// with their generated value.
func bindValues(keyvals []interface{}) {
for i := 1; i < len(keyvals); i += 2 {
if v, ok := keyvals[i].(Valuer); ok {
keyvals[i] = v()
}
}
}
// containsValuer returns true if any of the value elements (odd indexes)
// contain a Valuer.
func containsValuer(keyvals []interface{}) bool {
for i := 1; i < len(keyvals); i += 2 {
if _, ok := keyvals[i].(Valuer); ok {
return true
}
}
return false
}
// Timestamp returns a timestamp Valuer. It invokes the t function to get the
// time; unless you are doing something tricky, pass time.Now.
//
// Most users will want to use DefaultTimestamp or DefaultTimestampUTC, which
// are TimestampFormats that use the RFC3339Nano format.
func Timestamp(t func() time.Time) Valuer {
return func() interface{} { return t() }
}
// TimestampFormat returns a timestamp Valuer with a custom time format. It
// invokes the t function to get the time to format; unless you are doing
// something tricky, pass time.Now. The layout string is passed to
// Time.Format.
//
// Most users will want to use DefaultTimestamp or DefaultTimestampUTC, which
// are TimestampFormats that use the RFC3339Nano format.
func TimestampFormat(t func() time.Time, layout string) Valuer {
return func() interface{} {
return timeFormat{
time: t(),
layout: layout,
}
}
}
// A timeFormat represents an instant in time and a layout used when
// marshaling to a text format.
type timeFormat struct {
time time.Time
layout string
}
func (tf timeFormat) String() string {
return tf.time.Format(tf.layout)
}
// MarshalText implements encoding.TextMarshaller.
func (tf timeFormat) MarshalText() (text []byte, err error) {
// The following code adapted from the standard library time.Time.Format
// method. Using the same undocumented magic constant to extend the size
// of the buffer as seen there.
b := make([]byte, 0, len(tf.layout)+10)
b = tf.time.AppendFormat(b, tf.layout)
return b, nil
}
// Caller returns a Valuer that returns a file and line from a specified depth
// in the callstack. Users will probably want to use DefaultCaller.
func Caller(depth int) Valuer {
return func() interface{} {
_, file, line, _ := runtime.Caller(depth)
idx := strings.LastIndexByte(file, '/')
// using idx+1 below handles both of following cases:
// idx == -1 because no "/" was found, or
// idx >= 0 and we want to start at the character after the found "/".
return file[idx+1:] + ":" + strconv.Itoa(line)
}
}
var (
// DefaultTimestamp is a Valuer that returns the current wallclock time,
// respecting time zones, when bound.
DefaultTimestamp = TimestampFormat(time.Now, time.RFC3339Nano)
// DefaultTimestampUTC is a Valuer that returns the current time in UTC
// when bound.
DefaultTimestampUTC = TimestampFormat(
func() time.Time { return time.Now().UTC() },
time.RFC3339Nano,
)
// DefaultCaller is a Valuer that returns the file and line where the Log
// method was invoked. It can only be used with log.With.
DefaultCaller = Caller(3)
)

1
vendor/github.com/go-logfmt/logfmt/.gitignore generated vendored Normal file
View File

@@ -0,0 +1 @@
.vscode/

82
vendor/github.com/go-logfmt/logfmt/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,82 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.6.0] - 2023-01-30
[0.6.0]: https://github.com/go-logfmt/logfmt/compare/v0.5.1...v0.6.0
### Added
- NewDecoderSize by [@alexanderjophus]
## [0.5.1] - 2021-08-18
[0.5.1]: https://github.com/go-logfmt/logfmt/compare/v0.5.0...v0.5.1
### Changed
- Update the `go.mod` file for Go 1.17 as described in the [Go 1.17 release
notes](https://golang.org/doc/go1.17#go-command)
## [0.5.0] - 2020-01-03
[0.5.0]: https://github.com/go-logfmt/logfmt/compare/v0.4.0...v0.5.0
### Changed
- Remove the dependency on github.com/kr/logfmt by [@ChrisHines]
- Move fuzz code to github.com/go-logfmt/fuzzlogfmt by [@ChrisHines]
## [0.4.0] - 2018-11-21
[0.4.0]: https://github.com/go-logfmt/logfmt/compare/v0.3.0...v0.4.0
### Added
- Go module support by [@ChrisHines]
- CHANGELOG by [@ChrisHines]
### Changed
- Drop invalid runes from keys instead of returning ErrInvalidKey by [@ChrisHines]
- On panic while printing, attempt to print panic value by [@bboreham]
## [0.3.0] - 2016-11-15
[0.3.0]: https://github.com/go-logfmt/logfmt/compare/v0.2.0...v0.3.0
### Added
- Pool buffers for quoted strings and byte slices by [@nussjustin]
### Fixed
- Fuzz fix, quote invalid UTF-8 values by [@judwhite]
## [0.2.0] - 2016-05-08
[0.2.0]: https://github.com/go-logfmt/logfmt/compare/v0.1.0...v0.2.0
### Added
- Encoder.EncodeKeyvals by [@ChrisHines]
## [0.1.0] - 2016-03-28
[0.1.0]: https://github.com/go-logfmt/logfmt/commits/v0.1.0
### Added
- Encoder by [@ChrisHines]
- Decoder by [@ChrisHines]
- MarshalKeyvals by [@ChrisHines]
[@ChrisHines]: https://github.com/ChrisHines
[@bboreham]: https://github.com/bboreham
[@judwhite]: https://github.com/judwhite
[@nussjustin]: https://github.com/nussjustin
[@alexanderjophus]: https://github.com/alexanderjophus

22
vendor/github.com/go-logfmt/logfmt/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 go-logfmt
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

41
vendor/github.com/go-logfmt/logfmt/README.md generated vendored Normal file
View File

@@ -0,0 +1,41 @@
# logfmt
[![Go Reference](https://pkg.go.dev/badge/github.com/go-logfmt/logfmt.svg)](https://pkg.go.dev/github.com/go-logfmt/logfmt)
[![Go Report Card](https://goreportcard.com/badge/go-logfmt/logfmt)](https://goreportcard.com/report/go-logfmt/logfmt)
[![Github Actions](https://github.com/go-logfmt/logfmt/actions/workflows/test.yml/badge.svg)](https://github.com/go-logfmt/logfmt/actions/workflows/test.yml)
[![Coverage Status](https://coveralls.io/repos/github/go-logfmt/logfmt/badge.svg?branch=master)](https://coveralls.io/github/go-logfmt/logfmt?branch=main)
Package logfmt implements utilities to marshal and unmarshal data in the [logfmt
format][fmt]. It provides an API similar to [encoding/json][json] and
[encoding/xml][xml].
[fmt]: https://brandur.org/logfmt
[json]: https://pkg.go.dev/encoding/json
[xml]: https://pkg.go.dev/encoding/xml
The logfmt format was first documented by Brandur Leach in [this
article][origin]. The format has not been formally standardized. The most
authoritative public specification to date has been the documentation of a Go
Language [package][parser] written by Blake Mizerany and Keith Rarick.
[origin]: https://brandur.org/logfmt
[parser]: https://pkg.go.dev/github.com/kr/logfmt
## Goals
This project attempts to conform as closely as possible to the prior art, while
also removing ambiguity where necessary to provide well behaved encoder and
decoder implementations.
## Non-goals
This project does not attempt to formally standardize the logfmt format. In the
event that logfmt is standardized this project would take conforming to the
standard as a goal.
## Versioning
This project publishes releases according to the Go language guidelines for
[developing and publishing modules][pub].
[pub]: https://go.dev/doc/modules/developing

254
vendor/github.com/go-logfmt/logfmt/decode.go generated vendored Normal file
View File

@@ -0,0 +1,254 @@
package logfmt
import (
"bufio"
"bytes"
"fmt"
"io"
"unicode/utf8"
)
// A Decoder reads and decodes logfmt records from an input stream.
type Decoder struct {
pos int
key []byte
value []byte
lineNum int
s *bufio.Scanner
err error
}
// NewDecoder returns a new decoder that reads from r.
//
// The decoder introduces its own buffering and may read data from r beyond
// the logfmt records requested.
func NewDecoder(r io.Reader) *Decoder {
dec := &Decoder{
s: bufio.NewScanner(r),
}
return dec
}
// NewDecoderSize returns a new decoder that reads from r.
//
// The decoder introduces its own buffering and may read data from r beyond
// the logfmt records requested.
// The size argument specifies the size of the initial buffer that the
// Decoder will use to read records from r.
// If a log line is longer than the size argument, the Decoder will return
// a bufio.ErrTooLong error.
func NewDecoderSize(r io.Reader, size int) *Decoder {
scanner := bufio.NewScanner(r)
scanner.Buffer(make([]byte, 0, size), size)
dec := &Decoder{
s: scanner,
}
return dec
}
// ScanRecord advances the Decoder to the next record, which can then be
// parsed with the ScanKeyval method. It returns false when decoding stops,
// either by reaching the end of the input or an error. After ScanRecord
// returns false, the Err method will return any error that occurred during
// decoding, except that if it was io.EOF, Err will return nil.
func (dec *Decoder) ScanRecord() bool {
if dec.err != nil {
return false
}
if !dec.s.Scan() {
dec.err = dec.s.Err()
return false
}
dec.lineNum++
dec.pos = 0
return true
}
// ScanKeyval advances the Decoder to the next key/value pair of the current
// record, which can then be retrieved with the Key and Value methods. It
// returns false when decoding stops, either by reaching the end of the
// current record or an error.
func (dec *Decoder) ScanKeyval() bool {
dec.key, dec.value = nil, nil
if dec.err != nil {
return false
}
line := dec.s.Bytes()
// garbage
for p, c := range line[dec.pos:] {
if c > ' ' {
dec.pos += p
goto key
}
}
dec.pos = len(line)
return false
key:
const invalidKeyError = "invalid key"
start, multibyte := dec.pos, false
for p, c := range line[dec.pos:] {
switch {
case c == '=':
dec.pos += p
if dec.pos > start {
dec.key = line[start:dec.pos]
if multibyte && bytes.ContainsRune(dec.key, utf8.RuneError) {
dec.syntaxError(invalidKeyError)
return false
}
}
if dec.key == nil {
dec.unexpectedByte(c)
return false
}
goto equal
case c == '"':
dec.pos += p
dec.unexpectedByte(c)
return false
case c <= ' ':
dec.pos += p
if dec.pos > start {
dec.key = line[start:dec.pos]
if multibyte && bytes.ContainsRune(dec.key, utf8.RuneError) {
dec.syntaxError(invalidKeyError)
return false
}
}
return true
case c >= utf8.RuneSelf:
multibyte = true
}
}
dec.pos = len(line)
if dec.pos > start {
dec.key = line[start:dec.pos]
if multibyte && bytes.ContainsRune(dec.key, utf8.RuneError) {
dec.syntaxError(invalidKeyError)
return false
}
}
return true
equal:
dec.pos++
if dec.pos >= len(line) {
return true
}
switch c := line[dec.pos]; {
case c <= ' ':
return true
case c == '"':
goto qvalue
}
// value
start = dec.pos
for p, c := range line[dec.pos:] {
switch {
case c == '=' || c == '"':
dec.pos += p
dec.unexpectedByte(c)
return false
case c <= ' ':
dec.pos += p
if dec.pos > start {
dec.value = line[start:dec.pos]
}
return true
}
}
dec.pos = len(line)
if dec.pos > start {
dec.value = line[start:dec.pos]
}
return true
qvalue:
const (
untermQuote = "unterminated quoted value"
invalidQuote = "invalid quoted value"
)
hasEsc, esc := false, false
start = dec.pos
for p, c := range line[dec.pos+1:] {
switch {
case esc:
esc = false
case c == '\\':
hasEsc, esc = true, true
case c == '"':
dec.pos += p + 2
if hasEsc {
v, ok := unquoteBytes(line[start:dec.pos])
if !ok {
dec.syntaxError(invalidQuote)
return false
}
dec.value = v
} else {
start++
end := dec.pos - 1
if end > start {
dec.value = line[start:end]
}
}
return true
}
}
dec.pos = len(line)
dec.syntaxError(untermQuote)
return false
}
// Key returns the most recent key found by a call to ScanKeyval. The returned
// slice may point to internal buffers and is only valid until the next call
// to ScanRecord. It does no allocation.
func (dec *Decoder) Key() []byte {
return dec.key
}
// Value returns the most recent value found by a call to ScanKeyval. The
// returned slice may point to internal buffers and is only valid until the
// next call to ScanRecord. It does no allocation when the value has no
// escape sequences.
func (dec *Decoder) Value() []byte {
return dec.value
}
// Err returns the first non-EOF error that was encountered by the Scanner.
func (dec *Decoder) Err() error {
return dec.err
}
func (dec *Decoder) syntaxError(msg string) {
dec.err = &SyntaxError{
Msg: msg,
Line: dec.lineNum,
Pos: dec.pos + 1,
}
}
func (dec *Decoder) unexpectedByte(c byte) {
dec.err = &SyntaxError{
Msg: fmt.Sprintf("unexpected %q", c),
Line: dec.lineNum,
Pos: dec.pos + 1,
}
}
// A SyntaxError represents a syntax error in the logfmt input stream.
type SyntaxError struct {
Msg string
Line int
Pos int
}
func (e *SyntaxError) Error() string {
return fmt.Sprintf("logfmt syntax error at pos %d on line %d: %s", e.Pos, e.Line, e.Msg)
}

6
vendor/github.com/go-logfmt/logfmt/doc.go generated vendored Normal file
View File

@@ -0,0 +1,6 @@
// Package logfmt implements utilities to marshal and unmarshal data in the
// logfmt format. The logfmt format records key/value pairs in a way that
// balances readability for humans and simplicity of computer parsing. It is
// most commonly used as a more human friendly alternative to JSON for
// structured logging.
package logfmt

322
vendor/github.com/go-logfmt/logfmt/encode.go generated vendored Normal file
View File

@@ -0,0 +1,322 @@
package logfmt
import (
"bytes"
"encoding"
"errors"
"fmt"
"io"
"reflect"
"strings"
"unicode/utf8"
)
// MarshalKeyvals returns the logfmt encoding of keyvals, a variadic sequence
// of alternating keys and values.
func MarshalKeyvals(keyvals ...interface{}) ([]byte, error) {
buf := &bytes.Buffer{}
if err := NewEncoder(buf).EncodeKeyvals(keyvals...); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// An Encoder writes logfmt data to an output stream.
type Encoder struct {
w io.Writer
scratch bytes.Buffer
needSep bool
}
// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{
w: w,
}
}
var (
space = []byte(" ")
equals = []byte("=")
newline = []byte("\n")
null = []byte("null")
)
// EncodeKeyval writes the logfmt encoding of key and value to the stream. A
// single space is written before the second and subsequent keys in a record.
// Nothing is written if a non-nil error is returned.
func (enc *Encoder) EncodeKeyval(key, value interface{}) error {
enc.scratch.Reset()
if enc.needSep {
if _, err := enc.scratch.Write(space); err != nil {
return err
}
}
if err := writeKey(&enc.scratch, key); err != nil {
return err
}
if _, err := enc.scratch.Write(equals); err != nil {
return err
}
if err := writeValue(&enc.scratch, value); err != nil {
return err
}
_, err := enc.w.Write(enc.scratch.Bytes())
enc.needSep = true
return err
}
// EncodeKeyvals writes the logfmt encoding of keyvals to the stream. Keyvals
// is a variadic sequence of alternating keys and values. Keys of unsupported
// type are skipped along with their corresponding value. Values of
// unsupported type or that cause a MarshalerError are replaced by their error
// but do not cause EncodeKeyvals to return an error. If a non-nil error is
// returned some key/value pairs may not have be written.
func (enc *Encoder) EncodeKeyvals(keyvals ...interface{}) error {
if len(keyvals) == 0 {
return nil
}
if len(keyvals)%2 == 1 {
keyvals = append(keyvals, nil)
}
for i := 0; i < len(keyvals); i += 2 {
k, v := keyvals[i], keyvals[i+1]
err := enc.EncodeKeyval(k, v)
if err == ErrUnsupportedKeyType {
continue
}
if _, ok := err.(*MarshalerError); ok || err == ErrUnsupportedValueType {
v = err
err = enc.EncodeKeyval(k, v)
}
if err != nil {
return err
}
}
return nil
}
// MarshalerError represents an error encountered while marshaling a value.
type MarshalerError struct {
Type reflect.Type
Err error
}
func (e *MarshalerError) Error() string {
return "error marshaling value of type " + e.Type.String() + ": " + e.Err.Error()
}
// ErrNilKey is returned by Marshal functions and Encoder methods if a key is
// a nil interface or pointer value.
var ErrNilKey = errors.New("nil key")
// ErrInvalidKey is returned by Marshal functions and Encoder methods if, after
// dropping invalid runes, a key is empty.
var ErrInvalidKey = errors.New("invalid key")
// ErrUnsupportedKeyType is returned by Encoder methods if a key has an
// unsupported type.
var ErrUnsupportedKeyType = errors.New("unsupported key type")
// ErrUnsupportedValueType is returned by Encoder methods if a value has an
// unsupported type.
var ErrUnsupportedValueType = errors.New("unsupported value type")
func writeKey(w io.Writer, key interface{}) error {
if key == nil {
return ErrNilKey
}
switch k := key.(type) {
case string:
return writeStringKey(w, k)
case []byte:
if k == nil {
return ErrNilKey
}
return writeBytesKey(w, k)
case encoding.TextMarshaler:
kb, err := safeMarshal(k)
if err != nil {
return err
}
if kb == nil {
return ErrNilKey
}
return writeBytesKey(w, kb)
case fmt.Stringer:
ks, ok := safeString(k)
if !ok {
return ErrNilKey
}
return writeStringKey(w, ks)
default:
rkey := reflect.ValueOf(key)
switch rkey.Kind() {
case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct:
return ErrUnsupportedKeyType
case reflect.Ptr:
if rkey.IsNil() {
return ErrNilKey
}
return writeKey(w, rkey.Elem().Interface())
}
return writeStringKey(w, fmt.Sprint(k))
}
}
// keyRuneFilter returns r for all valid key runes, and -1 for all invalid key
// runes. When used as the mapping function for strings.Map and bytes.Map
// functions it causes them to remove invalid key runes from strings or byte
// slices respectively.
func keyRuneFilter(r rune) rune {
if r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError {
return -1
}
return r
}
func writeStringKey(w io.Writer, key string) error {
k := strings.Map(keyRuneFilter, key)
if k == "" {
return ErrInvalidKey
}
_, err := io.WriteString(w, k)
return err
}
func writeBytesKey(w io.Writer, key []byte) error {
k := bytes.Map(keyRuneFilter, key)
if len(k) == 0 {
return ErrInvalidKey
}
_, err := w.Write(k)
return err
}
func writeValue(w io.Writer, value interface{}) error {
switch v := value.(type) {
case nil:
return writeBytesValue(w, null)
case string:
return writeStringValue(w, v, true)
case []byte:
return writeBytesValue(w, v)
case encoding.TextMarshaler:
vb, err := safeMarshal(v)
if err != nil {
return err
}
if vb == nil {
vb = null
}
return writeBytesValue(w, vb)
case error:
se, ok := safeError(v)
return writeStringValue(w, se, ok)
case fmt.Stringer:
ss, ok := safeString(v)
return writeStringValue(w, ss, ok)
default:
rvalue := reflect.ValueOf(value)
switch rvalue.Kind() {
case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct:
return ErrUnsupportedValueType
case reflect.Ptr:
if rvalue.IsNil() {
return writeBytesValue(w, null)
}
return writeValue(w, rvalue.Elem().Interface())
}
return writeStringValue(w, fmt.Sprint(v), true)
}
}
func needsQuotedValueRune(r rune) bool {
return r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError
}
func writeStringValue(w io.Writer, value string, ok bool) error {
var err error
if ok && value == "null" {
_, err = io.WriteString(w, `"null"`)
} else if strings.IndexFunc(value, needsQuotedValueRune) != -1 {
_, err = writeQuotedString(w, value)
} else {
_, err = io.WriteString(w, value)
}
return err
}
func writeBytesValue(w io.Writer, value []byte) error {
var err error
if bytes.IndexFunc(value, needsQuotedValueRune) != -1 {
_, err = writeQuotedBytes(w, value)
} else {
_, err = w.Write(value)
}
return err
}
// EndRecord writes a newline character to the stream and resets the encoder
// to the beginning of a new record.
func (enc *Encoder) EndRecord() error {
_, err := enc.w.Write(newline)
if err == nil {
enc.needSep = false
}
return err
}
// Reset resets the encoder to the beginning of a new record.
func (enc *Encoder) Reset() {
enc.needSep = false
}
func safeError(err error) (s string, ok bool) {
defer func() {
if panicVal := recover(); panicVal != nil {
if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() {
s, ok = "null", false
} else {
s, ok = fmt.Sprintf("PANIC:%v", panicVal), false
}
}
}()
s, ok = err.Error(), true
return
}
func safeString(str fmt.Stringer) (s string, ok bool) {
defer func() {
if panicVal := recover(); panicVal != nil {
if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() {
s, ok = "null", false
} else {
s, ok = fmt.Sprintf("PANIC:%v", panicVal), true
}
}
}()
s, ok = str.String(), true
return
}
func safeMarshal(tm encoding.TextMarshaler) (b []byte, err error) {
defer func() {
if panicVal := recover(); panicVal != nil {
if v := reflect.ValueOf(tm); v.Kind() == reflect.Ptr && v.IsNil() {
b, err = nil, nil
} else {
b, err = nil, fmt.Errorf("panic when marshalling: %s", panicVal)
}
}
}()
b, err = tm.MarshalText()
if err != nil {
return nil, &MarshalerError{
Type: reflect.TypeOf(tm),
Err: err,
}
}
return
}

277
vendor/github.com/go-logfmt/logfmt/jsonstring.go generated vendored Normal file
View File

@@ -0,0 +1,277 @@
package logfmt
import (
"bytes"
"io"
"strconv"
"sync"
"unicode"
"unicode/utf16"
"unicode/utf8"
)
// Taken from Go's encoding/json and modified for use here.
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
var hex = "0123456789abcdef"
var bufferPool = sync.Pool{
New: func() interface{} {
return &bytes.Buffer{}
},
}
func getBuffer() *bytes.Buffer {
return bufferPool.Get().(*bytes.Buffer)
}
func poolBuffer(buf *bytes.Buffer) {
buf.Reset()
bufferPool.Put(buf)
}
// NOTE: keep in sync with writeQuotedBytes below.
func writeQuotedString(w io.Writer, s string) (int, error) {
buf := getBuffer()
buf.WriteByte('"')
start := 0
for i := 0; i < len(s); {
if b := s[i]; b < utf8.RuneSelf {
if 0x20 <= b && b != '\\' && b != '"' {
i++
continue
}
if start < i {
buf.WriteString(s[start:i])
}
switch b {
case '\\', '"':
buf.WriteByte('\\')
buf.WriteByte(b)
case '\n':
buf.WriteByte('\\')
buf.WriteByte('n')
case '\r':
buf.WriteByte('\\')
buf.WriteByte('r')
case '\t':
buf.WriteByte('\\')
buf.WriteByte('t')
default:
// This encodes bytes < 0x20 except for \n, \r, and \t.
buf.WriteString(`\u00`)
buf.WriteByte(hex[b>>4])
buf.WriteByte(hex[b&0xF])
}
i++
start = i
continue
}
c, size := utf8.DecodeRuneInString(s[i:])
if c == utf8.RuneError {
if start < i {
buf.WriteString(s[start:i])
}
buf.WriteString(`\ufffd`)
i += size
start = i
continue
}
i += size
}
if start < len(s) {
buf.WriteString(s[start:])
}
buf.WriteByte('"')
n, err := w.Write(buf.Bytes())
poolBuffer(buf)
return n, err
}
// NOTE: keep in sync with writeQuoteString above.
func writeQuotedBytes(w io.Writer, s []byte) (int, error) {
buf := getBuffer()
buf.WriteByte('"')
start := 0
for i := 0; i < len(s); {
if b := s[i]; b < utf8.RuneSelf {
if 0x20 <= b && b != '\\' && b != '"' {
i++
continue
}
if start < i {
buf.Write(s[start:i])
}
switch b {
case '\\', '"':
buf.WriteByte('\\')
buf.WriteByte(b)
case '\n':
buf.WriteByte('\\')
buf.WriteByte('n')
case '\r':
buf.WriteByte('\\')
buf.WriteByte('r')
case '\t':
buf.WriteByte('\\')
buf.WriteByte('t')
default:
// This encodes bytes < 0x20 except for \n, \r, and \t.
buf.WriteString(`\u00`)
buf.WriteByte(hex[b>>4])
buf.WriteByte(hex[b&0xF])
}
i++
start = i
continue
}
c, size := utf8.DecodeRune(s[i:])
if c == utf8.RuneError {
if start < i {
buf.Write(s[start:i])
}
buf.WriteString(`\ufffd`)
i += size
start = i
continue
}
i += size
}
if start < len(s) {
buf.Write(s[start:])
}
buf.WriteByte('"')
n, err := w.Write(buf.Bytes())
poolBuffer(buf)
return n, err
}
// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
// or it returns -1.
func getu4(s []byte) rune {
if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
return -1
}
r, err := strconv.ParseUint(string(s[2:6]), 16, 64)
if err != nil {
return -1
}
return rune(r)
}
func unquoteBytes(s []byte) (t []byte, ok bool) {
if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
return
}
s = s[1 : len(s)-1]
// Check for unusual characters. If there are none,
// then no unquoting is needed, so return a slice of the
// original bytes.
r := 0
for r < len(s) {
c := s[r]
if c == '\\' || c == '"' || c < ' ' {
break
}
if c < utf8.RuneSelf {
r++
continue
}
rr, size := utf8.DecodeRune(s[r:])
if rr == utf8.RuneError {
break
}
r += size
}
if r == len(s) {
return s, true
}
b := make([]byte, len(s)+2*utf8.UTFMax)
w := copy(b, s[0:r])
for r < len(s) {
// Out of room? Can only happen if s is full of
// malformed UTF-8 and we're replacing each
// byte with RuneError.
if w >= len(b)-2*utf8.UTFMax {
nb := make([]byte, (len(b)+utf8.UTFMax)*2)
copy(nb, b[0:w])
b = nb
}
switch c := s[r]; {
case c == '\\':
r++
if r >= len(s) {
return
}
switch s[r] {
default:
return
case '"', '\\', '/', '\'':
b[w] = s[r]
r++
w++
case 'b':
b[w] = '\b'
r++
w++
case 'f':
b[w] = '\f'
r++
w++
case 'n':
b[w] = '\n'
r++
w++
case 'r':
b[w] = '\r'
r++
w++
case 't':
b[w] = '\t'
r++
w++
case 'u':
r--
rr := getu4(s[r:])
if rr < 0 {
return
}
r += 6
if utf16.IsSurrogate(rr) {
rr1 := getu4(s[r:])
if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar {
// A valid pair; consume.
r += 6
w += utf8.EncodeRune(b[w:], dec)
break
}
// Invalid surrogate; fall back to replacement rune.
rr = unicode.ReplacementChar
}
w += utf8.EncodeRune(b[w:], rr)
}
// Quote, control characters are invalid.
case c == '"', c < ' ':
return
// ASCII
case c < utf8.RuneSelf:
b[w] = c
r++
w++
// Coerce to well-formed UTF-8.
default:
rr, size := utf8.DecodeRune(s[r:])
r += size
w += utf8.EncodeRune(b[w:], rr)
}
}
return b[0:w], true
}

191
vendor/github.com/golang/groupcache/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,191 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, "control" means (i) the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
"Object" form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
"submitted" means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
2. Grant of Copyright License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
3. Grant of Patent License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
4. Redistribution.
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of
this License; and
You must cause any modified files to carry prominent notices stating that You
changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
5. Submission of Contributions.
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
6. Trademarks.
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
7. Disclaimer of Warranty.
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
8. Limitation of Liability.
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability.
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets "[]" replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification within
third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

133
vendor/github.com/golang/groupcache/lru/lru.go generated vendored Normal file
View File

@@ -0,0 +1,133 @@
/*
Copyright 2013 Google Inc.
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 lru implements an LRU cache.
package lru
import "container/list"
// Cache is an LRU cache. It is not safe for concurrent access.
type Cache struct {
// MaxEntries is the maximum number of cache entries before
// an item is evicted. Zero means no limit.
MaxEntries int
// OnEvicted optionally specifies a callback function to be
// executed when an entry is purged from the cache.
OnEvicted func(key Key, value interface{})
ll *list.List
cache map[interface{}]*list.Element
}
// A Key may be any value that is comparable. See http://golang.org/ref/spec#Comparison_operators
type Key interface{}
type entry struct {
key Key
value interface{}
}
// New creates a new Cache.
// If maxEntries is zero, the cache has no limit and it's assumed
// that eviction is done by the caller.
func New(maxEntries int) *Cache {
return &Cache{
MaxEntries: maxEntries,
ll: list.New(),
cache: make(map[interface{}]*list.Element),
}
}
// Add adds a value to the cache.
func (c *Cache) Add(key Key, value interface{}) {
if c.cache == nil {
c.cache = make(map[interface{}]*list.Element)
c.ll = list.New()
}
if ee, ok := c.cache[key]; ok {
c.ll.MoveToFront(ee)
ee.Value.(*entry).value = value
return
}
ele := c.ll.PushFront(&entry{key, value})
c.cache[key] = ele
if c.MaxEntries != 0 && c.ll.Len() > c.MaxEntries {
c.RemoveOldest()
}
}
// Get looks up a key's value from the cache.
func (c *Cache) Get(key Key) (value interface{}, ok bool) {
if c.cache == nil {
return
}
if ele, hit := c.cache[key]; hit {
c.ll.MoveToFront(ele)
return ele.Value.(*entry).value, true
}
return
}
// Remove removes the provided key from the cache.
func (c *Cache) Remove(key Key) {
if c.cache == nil {
return
}
if ele, hit := c.cache[key]; hit {
c.removeElement(ele)
}
}
// RemoveOldest removes the oldest item from the cache.
func (c *Cache) RemoveOldest() {
if c.cache == nil {
return
}
ele := c.ll.Back()
if ele != nil {
c.removeElement(ele)
}
}
func (c *Cache) removeElement(e *list.Element) {
c.ll.Remove(e)
kv := e.Value.(*entry)
delete(c.cache, kv.key)
if c.OnEvicted != nil {
c.OnEvicted(kv.key, kv.value)
}
}
// Len returns the number of items in the cache.
func (c *Cache) Len() int {
if c.cache == nil {
return 0
}
return c.ll.Len()
}
// Clear purges all stored items from the cache.
func (c *Cache) Clear() {
if c.OnEvicted != nil {
for _, e := range c.cache {
kv := e.Value.(*entry)
c.OnEvicted(kv.key, kv.value)
}
}
c.ll = nil
c.cache = nil
}

3
vendor/github.com/golang/protobuf/AUTHORS generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.

3
vendor/github.com/golang/protobuf/CONTRIBUTORS generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.

28
vendor/github.com/golang/protobuf/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,28 @@
Copyright 2010 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,62 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: github.com/golang/protobuf/ptypes/empty/empty.proto
package empty
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb"
reflect "reflect"
)
// Symbols defined in public import of google/protobuf/empty.proto.
type Empty = emptypb.Empty
var File_github_com_golang_protobuf_ptypes_empty_empty_proto protoreflect.FileDescriptor
var file_github_com_golang_protobuf_ptypes_empty_empty_proto_rawDesc = []byte{
0x0a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
0x70, 0x65, 0x73, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x3b, 0x65, 0x6d,
0x70, 0x74, 0x79, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var file_github_com_golang_protobuf_ptypes_empty_empty_proto_goTypes = []interface{}{}
var file_github_com_golang_protobuf_ptypes_empty_empty_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_github_com_golang_protobuf_ptypes_empty_empty_proto_init() }
func file_github_com_golang_protobuf_ptypes_empty_empty_proto_init() {
if File_github_com_golang_protobuf_ptypes_empty_empty_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_github_com_golang_protobuf_ptypes_empty_empty_proto_rawDesc,
NumEnums: 0,
NumMessages: 0,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_github_com_golang_protobuf_ptypes_empty_empty_proto_goTypes,
DependencyIndexes: file_github_com_golang_protobuf_ptypes_empty_empty_proto_depIdxs,
}.Build()
File_github_com_golang_protobuf_ptypes_empty_empty_proto = out.File
file_github_com_golang_protobuf_ptypes_empty_empty_proto_rawDesc = nil
file_github_com_golang_protobuf_ptypes_empty_empty_proto_goTypes = nil
file_github_com_golang_protobuf_ptypes_empty_empty_proto_depIdxs = nil
}

View File

@@ -1,3 +1,3 @@
{
"v2": "2.14.1"
"v2": "2.13.0"
}

View File

@@ -1,24 +1,5 @@
# Changelog
## [2.14.1](https://github.com/googleapis/gax-go/compare/v2.14.0...v2.14.1) (2024-12-19)
### Bug Fixes
* update golang.org/x/net to v0.33.0 ([#391](https://github.com/googleapis/gax-go/issues/391)) ([547a5b4](https://github.com/googleapis/gax-go/commit/547a5b43aa6f376f71242da9f18e65fbdfb342f6))
### Documentation
* fix godoc to refer to the proper envvar ([#387](https://github.com/googleapis/gax-go/issues/387)) ([dc6baf7](https://github.com/googleapis/gax-go/commit/dc6baf75c1a737233739630b5af6c9759f08abcd))
## [2.14.0](https://github.com/googleapis/gax-go/compare/v2.13.0...v2.14.0) (2024-11-13)
### Features
* **internallog:** add a logging support package ([#380](https://github.com/googleapis/gax-go/issues/380)) ([c877470](https://github.com/googleapis/gax-go/commit/c87747098135631a3de5865ed03aaf2c79fd9319))
## [2.13.0](https://github.com/googleapis/gax-go/compare/v2.12.5...v2.13.0) (2024-07-22)

View File

@@ -30,4 +30,4 @@
package internal
// Version is the current tagged release of the library.
const Version = "2.14.1"
const Version = "2.13.0"

View File

@@ -1,134 +0,0 @@
// Copyright 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Package internal provides some common logic and types to other logging
// sub-packages.
package internal
import (
"context"
"io"
"log/slog"
"os"
"strings"
"time"
)
const (
// LoggingLevelEnvVar is the environment variable used to enable logging
// at a particular level.
LoggingLevelEnvVar = "GOOGLE_SDK_GO_LOGGING_LEVEL"
googLvlKey = "severity"
googMsgKey = "message"
googSourceKey = "sourceLocation"
googTimeKey = "timestamp"
)
// NewLoggerWithWriter is exposed for testing.
func NewLoggerWithWriter(w io.Writer) *slog.Logger {
lvl, loggingEnabled := checkLoggingLevel()
if !loggingEnabled {
return slog.New(noOpHandler{})
}
return slog.New(newGCPSlogHandler(lvl, w))
}
// checkLoggingLevel returned the configured logging level and whether or not
// logging is enabled.
func checkLoggingLevel() (slog.Leveler, bool) {
sLevel := strings.ToLower(os.Getenv(LoggingLevelEnvVar))
var level slog.Level
switch sLevel {
case "debug":
level = slog.LevelDebug
case "info":
level = slog.LevelInfo
case "warn":
level = slog.LevelWarn
case "error":
level = slog.LevelError
default:
return nil, false
}
return level, true
}
// newGCPSlogHandler returns a Handler that is configured to output in a JSON
// format with well-known keys. For more information on this format see
// https://cloud.google.com/logging/docs/agent/logging/configuration#special-fields.
func newGCPSlogHandler(lvl slog.Leveler, w io.Writer) slog.Handler {
return slog.NewJSONHandler(w, &slog.HandlerOptions{
Level: lvl,
ReplaceAttr: replaceAttr,
})
}
// replaceAttr remaps default Go logging keys to match what is expected in
// cloud logging.
func replaceAttr(groups []string, a slog.Attr) slog.Attr {
if groups == nil {
if a.Key == slog.LevelKey {
a.Key = googLvlKey
return a
} else if a.Key == slog.MessageKey {
a.Key = googMsgKey
return a
} else if a.Key == slog.SourceKey {
a.Key = googSourceKey
return a
} else if a.Key == slog.TimeKey {
a.Key = googTimeKey
if a.Value.Kind() == slog.KindTime {
a.Value = slog.StringValue(a.Value.Time().Format(time.RFC3339))
}
return a
}
}
return a
}
// The handler returned if logging is not enabled.
type noOpHandler struct{}
func (h noOpHandler) Enabled(_ context.Context, _ slog.Level) bool {
return false
}
func (h noOpHandler) Handle(_ context.Context, _ slog.Record) error {
return nil
}
func (h noOpHandler) WithAttrs(_ []slog.Attr) slog.Handler {
return h
}
func (h noOpHandler) WithGroup(_ string) slog.Handler {
return h
}

View File

@@ -1,154 +0,0 @@
// Copyright 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Package internallog in intended for internal use by generated clients only.
package internallog
import (
"bytes"
"encoding/json"
"fmt"
"log/slog"
"net/http"
"os"
"strings"
"github.com/googleapis/gax-go/v2/internallog/internal"
)
// New returns a new [slog.Logger] default logger, or the provided logger if
// non-nil. The returned logger will be a no-op logger unless the environment
// variable GOOGLE_SDK_GO_LOGGING_LEVEL is set.
func New(l *slog.Logger) *slog.Logger {
if l != nil {
return l
}
return internal.NewLoggerWithWriter(os.Stderr)
}
// HTTPRequest returns a lazily evaluated [slog.LogValuer] for a
// [http.Request] and the associated body.
func HTTPRequest(req *http.Request, body []byte) slog.LogValuer {
return &request{
req: req,
payload: body,
}
}
type request struct {
req *http.Request
payload []byte
}
func (r *request) LogValue() slog.Value {
if r == nil || r.req == nil {
return slog.Value{}
}
var groupValueAttrs []slog.Attr
groupValueAttrs = append(groupValueAttrs, slog.String("method", r.req.Method))
groupValueAttrs = append(groupValueAttrs, slog.String("url", r.req.URL.String()))
var headerAttr []slog.Attr
for k, val := range r.req.Header {
headerAttr = append(headerAttr, slog.String(k, strings.Join(val, ",")))
}
if len(headerAttr) > 0 {
groupValueAttrs = append(groupValueAttrs, slog.Any("headers", headerAttr))
}
if len(r.payload) > 0 {
if attr, ok := processPayload(r.payload); ok {
groupValueAttrs = append(groupValueAttrs, attr)
}
}
return slog.GroupValue(groupValueAttrs...)
}
// HTTPResponse returns a lazily evaluated [slog.LogValuer] for a
// [http.Response] and the associated body.
func HTTPResponse(resp *http.Response, body []byte) slog.LogValuer {
return &response{
resp: resp,
payload: body,
}
}
type response struct {
resp *http.Response
payload []byte
}
func (r *response) LogValue() slog.Value {
if r == nil {
return slog.Value{}
}
var groupValueAttrs []slog.Attr
groupValueAttrs = append(groupValueAttrs, slog.String("status", fmt.Sprint(r.resp.StatusCode)))
var headerAttr []slog.Attr
for k, val := range r.resp.Header {
headerAttr = append(headerAttr, slog.String(k, strings.Join(val, ",")))
}
if len(headerAttr) > 0 {
groupValueAttrs = append(groupValueAttrs, slog.Any("headers", headerAttr))
}
if len(r.payload) > 0 {
if attr, ok := processPayload(r.payload); ok {
groupValueAttrs = append(groupValueAttrs, attr)
}
}
return slog.GroupValue(groupValueAttrs...)
}
func processPayload(payload []byte) (slog.Attr, bool) {
peekChar := payload[0]
if peekChar == '{' {
// JSON object
var m map[string]any
if err := json.Unmarshal(payload, &m); err == nil {
return slog.Any("payload", m), true
}
} else if peekChar == '[' {
// JSON array
var m []any
if err := json.Unmarshal(payload, &m); err == nil {
return slog.Any("payload", m), true
}
} else {
// Everything else
buf := &bytes.Buffer{}
if err := json.Compact(buf, payload); err != nil {
// Write raw payload incase of error
buf.Write(payload)
}
return slog.String("payload", buf.String()), true
}
return slog.Attr{}, false
}

1
vendor/github.com/hashicorp/go-hclog/.gitignore generated vendored Normal file
View File

@@ -0,0 +1 @@
.idea*

19
vendor/github.com/hashicorp/go-hclog/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2017 HashiCorp, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

149
vendor/github.com/hashicorp/go-hclog/README.md generated vendored Normal file
View File

@@ -0,0 +1,149 @@
# go-hclog
[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs]
[godocs]: https://godoc.org/github.com/hashicorp/go-hclog
`go-hclog` is a package for Go that provides a simple key/value logging
interface for use in development and production environments.
It provides logging levels that provide decreased output based upon the
desired amount of output, unlike the standard library `log` package.
It provides `Printf` style logging of values via `hclog.Fmt()`.
It provides a human readable output mode for use in development as well as
JSON output mode for production.
## Stability Note
This library has reached 1.0 stability. Its API can be considered solidified
and promised through future versions.
## Installation and Docs
Install using `go get github.com/hashicorp/go-hclog`.
Full documentation is available at
http://godoc.org/github.com/hashicorp/go-hclog
## Usage
### Use the global logger
```go
hclog.Default().Info("hello world")
```
```text
2017-07-05T16:15:55.167-0700 [INFO ] hello world
```
(Note timestamps are removed in future examples for brevity.)
### Create a new logger
```go
appLogger := hclog.New(&hclog.LoggerOptions{
Name: "my-app",
Level: hclog.LevelFromString("DEBUG"),
})
```
### Emit an Info level message with 2 key/value pairs
```go
input := "5.5"
_, err := strconv.ParseInt(input, 10, 32)
if err != nil {
appLogger.Info("Invalid input for ParseInt", "input", input, "error", err)
}
```
```text
... [INFO ] my-app: Invalid input for ParseInt: input=5.5 error="strconv.ParseInt: parsing "5.5": invalid syntax"
```
### Create a new Logger for a major subsystem
```go
subsystemLogger := appLogger.Named("transport")
subsystemLogger.Info("we are transporting something")
```
```text
... [INFO ] my-app.transport: we are transporting something
```
Notice that logs emitted by `subsystemLogger` contain `my-app.transport`,
reflecting both the application and subsystem names.
### Create a new Logger with fixed key/value pairs
Using `With()` will include a specific key-value pair in all messages emitted
by that logger.
```go
requestID := "5fb446b6-6eba-821d-df1b-cd7501b6a363"
requestLogger := subsystemLogger.With("request", requestID)
requestLogger.Info("we are transporting a request")
```
```text
... [INFO ] my-app.transport: we are transporting a request: request=5fb446b6-6eba-821d-df1b-cd7501b6a363
```
This allows sub Loggers to be context specific without having to thread that
into all the callers.
### Using `hclog.Fmt()`
```go
totalBandwidth := 200
appLogger.Info("total bandwidth exceeded", "bandwidth", hclog.Fmt("%d GB/s", totalBandwidth))
```
```text
... [INFO ] my-app: total bandwidth exceeded: bandwidth="200 GB/s"
```
### Use this with code that uses the standard library logger
If you want to use the standard library's `log.Logger` interface you can wrap
`hclog.Logger` by calling the `StandardLogger()` method. This allows you to use
it with the familiar `Println()`, `Printf()`, etc. For example:
```go
stdLogger := appLogger.StandardLogger(&hclog.StandardLoggerOptions{
InferLevels: true,
})
// Printf() is provided by stdlib log.Logger interface, not hclog.Logger
stdLogger.Printf("[DEBUG] %+v", stdLogger)
```
```text
... [DEBUG] my-app: &{mu:{state:0 sema:0} prefix: flag:0 out:0xc42000a0a0 buf:[]}
```
Alternatively, you may configure the system-wide logger:
```go
// log the standard logger from 'import "log"'
log.SetOutput(appLogger.StandardWriter(&hclog.StandardLoggerOptions{InferLevels: true}))
log.SetPrefix("")
log.SetFlags(0)
log.Printf("[DEBUG] %d", 42)
```
```text
... [DEBUG] my-app: 42
```
Notice that if `appLogger` is initialized with the `INFO` log level, _and_ you
specify `InferLevels: true`, you will not see any output here. You must change
`appLogger` to `DEBUG` to see output. See the docs for more information.
If the log lines start with a timestamp you can use the
`InferLevelsWithTimestamp` option to try and ignore them. Please note that in order
for `InferLevelsWithTimestamp` to be relevant, `InferLevels` must be set to `true`.

44
vendor/github.com/hashicorp/go-hclog/colorize_unix.go generated vendored Normal file
View File

@@ -0,0 +1,44 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MIT
//go:build !windows
// +build !windows
package hclog
import (
"github.com/mattn/go-isatty"
)
// hasFD is used to check if the writer has an Fd value to check
// if it's a terminal.
type hasFD interface {
Fd() uintptr
}
// setColorization will mutate the values of this logger
// to appropriately configure colorization options. It provides
// a wrapper to the output stream on Windows systems.
func (l *intLogger) setColorization(opts *LoggerOptions) {
if opts.Color != AutoColor {
return
}
if sc, ok := l.writer.w.(SupportsColor); ok {
if !sc.SupportsColor() {
l.headerColor = ColorOff
l.writer.color = ColorOff
}
return
}
fi, ok := l.writer.w.(hasFD)
if !ok {
return
}
if !isatty.IsTerminal(fi.Fd()) {
l.headerColor = ColorOff
l.writer.color = ColorOff
}
}

View File

@@ -0,0 +1,41 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MIT
//go:build windows
// +build windows
package hclog
import (
"os"
colorable "github.com/mattn/go-colorable"
)
// setColorization will mutate the values of this logger
// to appropriately configure colorization options. It provides
// a wrapper to the output stream on Windows systems.
func (l *intLogger) setColorization(opts *LoggerOptions) {
if opts.Color == ColorOff {
return
}
fi, ok := l.writer.w.(*os.File)
if !ok {
l.writer.color = ColorOff
l.headerColor = ColorOff
return
}
cfi := colorable.NewColorable(fi)
// NewColorable detects if color is possible and if it's not, then it
// returns the original value. So we can test if we got the original
// value back to know if color is possible.
if cfi == fi {
l.writer.color = ColorOff
l.headerColor = ColorOff
} else {
l.writer.w = cfi
}
}

41
vendor/github.com/hashicorp/go-hclog/context.go generated vendored Normal file
View File

@@ -0,0 +1,41 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MIT
package hclog
import (
"context"
)
// WithContext inserts a logger into the context and is retrievable
// with FromContext. The optional args can be set with the same syntax as
// Logger.With to set fields on the inserted logger. This will not modify
// the logger argument in-place.
func WithContext(ctx context.Context, logger Logger, args ...interface{}) context.Context {
// While we could call logger.With even with zero args, we have this
// check to avoid unnecessary allocations around creating a copy of a
// logger.
if len(args) > 0 {
logger = logger.With(args...)
}
return context.WithValue(ctx, contextKey, logger)
}
// FromContext returns a logger from the context. This will return L()
// (the default logger) if no logger is found in the context. Therefore,
// this will never return a nil value.
func FromContext(ctx context.Context) Logger {
logger, _ := ctx.Value(contextKey).(Logger)
if logger == nil {
return L()
}
return logger
}
// Unexported new type so that our context key never collides with another.
type contextKeyType struct{}
// contextKey is the key used for the context to store the logger.
var contextKey = contextKeyType{}

74
vendor/github.com/hashicorp/go-hclog/exclude.go generated vendored Normal file
View File

@@ -0,0 +1,74 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MIT
package hclog
import (
"regexp"
"strings"
)
// ExcludeByMessage provides a simple way to build a list of log messages that
// can be queried and matched. This is meant to be used with the Exclude
// option on Options to suppress log messages. This does not hold any mutexs
// within itself, so normal usage would be to Add entries at setup and none after
// Exclude is going to be called. Exclude is called with a mutex held within
// the Logger, so that doesn't need to use a mutex. Example usage:
//
// f := new(ExcludeByMessage)
// f.Add("Noisy log message text")
// appLogger.Exclude = f.Exclude
type ExcludeByMessage struct {
messages map[string]struct{}
}
// Add a message to be filtered. Do not call this after Exclude is to be called
// due to concurrency issues.
func (f *ExcludeByMessage) Add(msg string) {
if f.messages == nil {
f.messages = make(map[string]struct{})
}
f.messages[msg] = struct{}{}
}
// Return true if the given message should be included
func (f *ExcludeByMessage) Exclude(level Level, msg string, args ...interface{}) bool {
_, ok := f.messages[msg]
return ok
}
// ExcludeByPrefix is a simple type to match a message string that has a common prefix.
type ExcludeByPrefix string
// Matches an message that starts with the prefix.
func (p ExcludeByPrefix) Exclude(level Level, msg string, args ...interface{}) bool {
return strings.HasPrefix(msg, string(p))
}
// ExcludeByRegexp takes a regexp and uses it to match a log message string. If it matches
// the log entry is excluded.
type ExcludeByRegexp struct {
Regexp *regexp.Regexp
}
// Exclude the log message if the message string matches the regexp
func (e ExcludeByRegexp) Exclude(level Level, msg string, args ...interface{}) bool {
return e.Regexp.MatchString(msg)
}
// ExcludeFuncs is a slice of functions that will called to see if a log entry
// should be filtered or not. It stops calling functions once at least one returns
// true.
type ExcludeFuncs []func(level Level, msg string, args ...interface{}) bool
// Calls each function until one of them returns true
func (ff ExcludeFuncs) Exclude(level Level, msg string, args ...interface{}) bool {
for _, f := range ff {
if f(level, msg, args...) {
return true
}
}
return false
}

67
vendor/github.com/hashicorp/go-hclog/global.go generated vendored Normal file
View File

@@ -0,0 +1,67 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MIT
package hclog
import (
"sync"
"time"
)
var (
protect sync.Once
def Logger
// DefaultOptions is used to create the Default logger. These are read
// only when the Default logger is created, so set them as soon as the
// process starts.
DefaultOptions = &LoggerOptions{
Level: DefaultLevel,
Output: DefaultOutput,
TimeFn: time.Now,
}
)
// Default returns a globally held logger. This can be a good starting
// place, and then you can use .With() and .Named() to create sub-loggers
// to be used in more specific contexts.
// The value of the Default logger can be set via SetDefault() or by
// changing the options in DefaultOptions.
//
// This method is goroutine safe, returning a global from memory, but
// care should be used if SetDefault() is called it random times
// in the program as that may result in race conditions and an unexpected
// Logger being returned.
func Default() Logger {
protect.Do(func() {
// If SetDefault was used before Default() was called, we need to
// detect that here.
if def == nil {
def = New(DefaultOptions)
}
})
return def
}
// L is a short alias for Default().
func L() Logger {
return Default()
}
// SetDefault changes the logger to be returned by Default()and L()
// to the one given. This allows packages to use the default logger
// and have higher level packages change it to match the execution
// environment. It returns any old default if there is one.
//
// NOTE: This is expected to be called early in the program to setup
// a default logger. As such, it does not attempt to make itself
// not racy with regard to the value of the default logger. Ergo
// if it is called in goroutines, you may experience race conditions
// with other goroutines retrieving the default logger. Basically,
// don't do that.
func SetDefault(log Logger) Logger {
old := def
def = log
return old
}

207
vendor/github.com/hashicorp/go-hclog/interceptlogger.go generated vendored Normal file
View File

@@ -0,0 +1,207 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MIT
package hclog
import (
"io"
"log"
"sync"
"sync/atomic"
)
var _ Logger = &interceptLogger{}
type interceptLogger struct {
Logger
mu *sync.Mutex
sinkCount *int32
Sinks map[SinkAdapter]struct{}
}
func NewInterceptLogger(opts *LoggerOptions) InterceptLogger {
l := newLogger(opts)
if l.callerOffset > 0 {
// extra frames for interceptLogger.{Warn,Info,Log,etc...}, and interceptLogger.log
l.callerOffset += 2
}
intercept := &interceptLogger{
Logger: l,
mu: new(sync.Mutex),
sinkCount: new(int32),
Sinks: make(map[SinkAdapter]struct{}),
}
atomic.StoreInt32(intercept.sinkCount, 0)
return intercept
}
func (i *interceptLogger) Log(level Level, msg string, args ...interface{}) {
i.log(level, msg, args...)
}
// log is used to make the caller stack frame lookup consistent. If Warn,Info,etc
// all called Log then direct calls to Log would have a different stack frame
// depth. By having all the methods call the same helper we ensure the stack
// frame depth is the same.
func (i *interceptLogger) log(level Level, msg string, args ...interface{}) {
i.Logger.Log(level, msg, args...)
if atomic.LoadInt32(i.sinkCount) == 0 {
return
}
i.mu.Lock()
defer i.mu.Unlock()
for s := range i.Sinks {
s.Accept(i.Name(), level, msg, i.retrieveImplied(args...)...)
}
}
// Emit the message and args at TRACE level to log and sinks
func (i *interceptLogger) Trace(msg string, args ...interface{}) {
i.log(Trace, msg, args...)
}
// Emit the message and args at DEBUG level to log and sinks
func (i *interceptLogger) Debug(msg string, args ...interface{}) {
i.log(Debug, msg, args...)
}
// Emit the message and args at INFO level to log and sinks
func (i *interceptLogger) Info(msg string, args ...interface{}) {
i.log(Info, msg, args...)
}
// Emit the message and args at WARN level to log and sinks
func (i *interceptLogger) Warn(msg string, args ...interface{}) {
i.log(Warn, msg, args...)
}
// Emit the message and args at ERROR level to log and sinks
func (i *interceptLogger) Error(msg string, args ...interface{}) {
i.log(Error, msg, args...)
}
func (i *interceptLogger) retrieveImplied(args ...interface{}) []interface{} {
top := i.Logger.ImpliedArgs()
cp := make([]interface{}, len(top)+len(args))
copy(cp, top)
copy(cp[len(top):], args)
return cp
}
// Create a new sub-Logger that a name descending from the current name.
// This is used to create a subsystem specific Logger.
// Registered sinks will subscribe to these messages as well.
func (i *interceptLogger) Named(name string) Logger {
return i.NamedIntercept(name)
}
// Create a new sub-Logger with an explicit name. This ignores the current
// name. This is used to create a standalone logger that doesn't fall
// within the normal hierarchy. Registered sinks will subscribe
// to these messages as well.
func (i *interceptLogger) ResetNamed(name string) Logger {
return i.ResetNamedIntercept(name)
}
// Create a new sub-Logger that a name decending from the current name.
// This is used to create a subsystem specific Logger.
// Registered sinks will subscribe to these messages as well.
func (i *interceptLogger) NamedIntercept(name string) InterceptLogger {
var sub interceptLogger
sub = *i
sub.Logger = i.Logger.Named(name)
return &sub
}
// Create a new sub-Logger with an explicit name. This ignores the current
// name. This is used to create a standalone logger that doesn't fall
// within the normal hierarchy. Registered sinks will subscribe
// to these messages as well.
func (i *interceptLogger) ResetNamedIntercept(name string) InterceptLogger {
var sub interceptLogger
sub = *i
sub.Logger = i.Logger.ResetNamed(name)
return &sub
}
// Return a sub-Logger for which every emitted log message will contain
// the given key/value pairs. This is used to create a context specific
// Logger.
func (i *interceptLogger) With(args ...interface{}) Logger {
var sub interceptLogger
sub = *i
sub.Logger = i.Logger.With(args...)
return &sub
}
// RegisterSink attaches a SinkAdapter to interceptLoggers sinks.
func (i *interceptLogger) RegisterSink(sink SinkAdapter) {
i.mu.Lock()
defer i.mu.Unlock()
i.Sinks[sink] = struct{}{}
atomic.AddInt32(i.sinkCount, 1)
}
// DeregisterSink removes a SinkAdapter from interceptLoggers sinks.
func (i *interceptLogger) DeregisterSink(sink SinkAdapter) {
i.mu.Lock()
defer i.mu.Unlock()
delete(i.Sinks, sink)
atomic.AddInt32(i.sinkCount, -1)
}
func (i *interceptLogger) StandardLoggerIntercept(opts *StandardLoggerOptions) *log.Logger {
return i.StandardLogger(opts)
}
func (i *interceptLogger) StandardLogger(opts *StandardLoggerOptions) *log.Logger {
if opts == nil {
opts = &StandardLoggerOptions{}
}
return log.New(i.StandardWriter(opts), "", 0)
}
func (i *interceptLogger) StandardWriterIntercept(opts *StandardLoggerOptions) io.Writer {
return i.StandardWriter(opts)
}
func (i *interceptLogger) StandardWriter(opts *StandardLoggerOptions) io.Writer {
return &stdlogAdapter{
log: i,
inferLevels: opts.InferLevels,
inferLevelsWithTimestamp: opts.InferLevelsWithTimestamp,
forceLevel: opts.ForceLevel,
}
}
func (i *interceptLogger) ResetOutput(opts *LoggerOptions) error {
if or, ok := i.Logger.(OutputResettable); ok {
return or.ResetOutput(opts)
} else {
return nil
}
}
func (i *interceptLogger) ResetOutputWithFlush(opts *LoggerOptions, flushable Flushable) error {
if or, ok := i.Logger.(OutputResettable); ok {
return or.ResetOutputWithFlush(opts, flushable)
} else {
return nil
}
}

1007
vendor/github.com/hashicorp/go-hclog/intlogger.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

415
vendor/github.com/hashicorp/go-hclog/logger.go generated vendored Normal file
View File

@@ -0,0 +1,415 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MIT
package hclog
import (
"io"
"log"
"os"
"strings"
"time"
)
var (
// DefaultOutput is used as the default log output.
DefaultOutput io.Writer = os.Stderr
// DefaultLevel is used as the default log level.
DefaultLevel = Info
)
// Level represents a log level.
type Level int32
const (
// NoLevel is a special level used to indicate that no level has been
// set and allow for a default to be used.
NoLevel Level = 0
// Trace is the most verbose level. Intended to be used for the tracing
// of actions in code, such as function enters/exits, etc.
Trace Level = 1
// Debug information for programmer low-level analysis.
Debug Level = 2
// Info information about steady state operations.
Info Level = 3
// Warn information about rare but handled events.
Warn Level = 4
// Error information about unrecoverable events.
Error Level = 5
// Off disables all logging output.
Off Level = 6
)
// Format is a simple convenience type for when formatting is required. When
// processing a value of this type, the logger automatically treats the first
// argument as a Printf formatting string and passes the rest as the values
// to be formatted. For example: L.Info(Fmt{"%d beans/day", beans}).
type Format []interface{}
// Fmt returns a Format type. This is a convenience function for creating a Format
// type.
func Fmt(str string, args ...interface{}) Format {
return append(Format{str}, args...)
}
// A simple shortcut to format numbers in hex when displayed with the normal
// text output. For example: L.Info("header value", Hex(17))
type Hex int
// A simple shortcut to format numbers in octal when displayed with the normal
// text output. For example: L.Info("perms", Octal(17))
type Octal int
// A simple shortcut to format numbers in binary when displayed with the normal
// text output. For example: L.Info("bits", Binary(17))
type Binary int
// A simple shortcut to format strings with Go quoting. Control and
// non-printable characters will be escaped with their backslash equivalents in
// output. Intended for untrusted or multiline strings which should be logged
// as concisely as possible.
type Quote string
// ColorOption expresses how the output should be colored, if at all.
type ColorOption uint8
const (
// ColorOff is the default coloration, and does not
// inject color codes into the io.Writer.
ColorOff ColorOption = iota
// AutoColor checks if the io.Writer is a tty,
// and if so enables coloring.
AutoColor
// ForceColor will enable coloring, regardless of whether
// the io.Writer is a tty or not.
ForceColor
)
// SupportsColor is an optional interface that can be implemented by the output
// value. If implemented and SupportsColor() returns true, then AutoColor will
// enable colorization.
type SupportsColor interface {
SupportsColor() bool
}
// LevelFromString returns a Level type for the named log level, or "NoLevel" if
// the level string is invalid. This facilitates setting the log level via
// config or environment variable by name in a predictable way.
func LevelFromString(levelStr string) Level {
// We don't care about case. Accept both "INFO" and "info".
levelStr = strings.ToLower(strings.TrimSpace(levelStr))
switch levelStr {
case "trace":
return Trace
case "debug":
return Debug
case "info":
return Info
case "warn":
return Warn
case "error":
return Error
case "off":
return Off
default:
return NoLevel
}
}
func (l Level) String() string {
switch l {
case Trace:
return "trace"
case Debug:
return "debug"
case Info:
return "info"
case Warn:
return "warn"
case Error:
return "error"
case NoLevel:
return "none"
case Off:
return "off"
default:
return "unknown"
}
}
// Logger describes the interface that must be implemented by all loggers.
type Logger interface {
// Args are alternating key, val pairs
// keys must be strings
// vals can be any type, but display is implementation specific
// Emit a message and key/value pairs at a provided log level
Log(level Level, msg string, args ...interface{})
// Emit a message and key/value pairs at the TRACE level
Trace(msg string, args ...interface{})
// Emit a message and key/value pairs at the DEBUG level
Debug(msg string, args ...interface{})
// Emit a message and key/value pairs at the INFO level
Info(msg string, args ...interface{})
// Emit a message and key/value pairs at the WARN level
Warn(msg string, args ...interface{})
// Emit a message and key/value pairs at the ERROR level
Error(msg string, args ...interface{})
// Indicate if TRACE logs would be emitted. This and the other Is* guards
// are used to elide expensive logging code based on the current level.
IsTrace() bool
// Indicate if DEBUG logs would be emitted. This and the other Is* guards
IsDebug() bool
// Indicate if INFO logs would be emitted. This and the other Is* guards
IsInfo() bool
// Indicate if WARN logs would be emitted. This and the other Is* guards
IsWarn() bool
// Indicate if ERROR logs would be emitted. This and the other Is* guards
IsError() bool
// ImpliedArgs returns With key/value pairs
ImpliedArgs() []interface{}
// Creates a sublogger that will always have the given key/value pairs
With(args ...interface{}) Logger
// Returns the Name of the logger
Name() string
// Create a logger that will prepend the name string on the front of all messages.
// If the logger already has a name, the new value will be appended to the current
// name. That way, a major subsystem can use this to decorate all it's own logs
// without losing context.
Named(name string) Logger
// Create a logger that will prepend the name string on the front of all messages.
// This sets the name of the logger to the value directly, unlike Named which honor
// the current name as well.
ResetNamed(name string) Logger
// Updates the level. This should affect all related loggers as well,
// unless they were created with IndependentLevels. If an
// implementation cannot update the level on the fly, it should no-op.
SetLevel(level Level)
// Returns the current level
GetLevel() Level
// Return a value that conforms to the stdlib log.Logger interface
StandardLogger(opts *StandardLoggerOptions) *log.Logger
// Return a value that conforms to io.Writer, which can be passed into log.SetOutput()
StandardWriter(opts *StandardLoggerOptions) io.Writer
}
// StandardLoggerOptions can be used to configure a new standard logger.
type StandardLoggerOptions struct {
// Indicate that some minimal parsing should be done on strings to try
// and detect their level and re-emit them.
// This supports the strings like [ERROR], [ERR] [TRACE], [WARN], [INFO],
// [DEBUG] and strip it off before reapplying it.
InferLevels bool
// Indicate that some minimal parsing should be done on strings to try
// and detect their level and re-emit them while ignoring possible
// timestamp values in the beginning of the string.
// This supports the strings like [ERROR], [ERR] [TRACE], [WARN], [INFO],
// [DEBUG] and strip it off before reapplying it.
// The timestamp detection may result in false positives and incomplete
// string outputs.
// InferLevelsWithTimestamp is only relevant if InferLevels is true.
InferLevelsWithTimestamp bool
// ForceLevel is used to force all output from the standard logger to be at
// the specified level. Similar to InferLevels, this will strip any level
// prefix contained in the logged string before applying the forced level.
// If set, this override InferLevels.
ForceLevel Level
}
type TimeFunction = func() time.Time
// LoggerOptions can be used to configure a new logger.
type LoggerOptions struct {
// Name of the subsystem to prefix logs with
Name string
// The threshold for the logger. Anything less severe is suppressed
Level Level
// Where to write the logs to. Defaults to os.Stderr if nil
Output io.Writer
// An optional Locker in case Output is shared. This can be a sync.Mutex or
// a NoopLocker if the caller wants control over output, e.g. for batching
// log lines.
Mutex Locker
// Control if the output should be in JSON.
JSONFormat bool
// Control the escape switch of json.Encoder
JSONEscapeDisabled bool
// Include file and line information in each log line
IncludeLocation bool
// AdditionalLocationOffset is the number of additional stack levels to skip
// when finding the file and line information for the log line
AdditionalLocationOffset int
// The time format to use instead of the default
TimeFormat string
// A function which is called to get the time object that is formatted using `TimeFormat`
TimeFn TimeFunction
// Control whether or not to display the time at all. This is required
// because setting TimeFormat to empty assumes the default format.
DisableTime bool
// Color the output. On Windows, colored logs are only available for io.Writers that
// are concretely instances of *os.File.
Color ColorOption
// Only color the header, not the body. This can help with readability of long messages.
ColorHeaderOnly bool
// Color the header and message body fields. This can help with readability
// of long messages with multiple fields.
ColorHeaderAndFields bool
// A function which is called with the log information and if it returns true the value
// should not be logged.
// This is useful when interacting with a system that you wish to suppress the log
// message for (because it's too noisy, etc)
Exclude func(level Level, msg string, args ...interface{}) bool
// IndependentLevels causes subloggers to be created with an independent
// copy of this logger's level. This means that using SetLevel on this
// logger will not affect any subloggers, and SetLevel on any subloggers
// will not affect the parent or sibling loggers.
IndependentLevels bool
// When set, changing the level of a logger effects only it's direct sub-loggers
// rather than all sub-loggers. For example:
// a := logger.Named("a")
// a.SetLevel(Error)
// b := a.Named("b")
// c := a.Named("c")
// b.GetLevel() => Error
// c.GetLevel() => Error
// b.SetLevel(Info)
// a.GetLevel() => Error
// b.GetLevel() => Info
// c.GetLevel() => Error
// a.SetLevel(Warn)
// a.GetLevel() => Warn
// b.GetLevel() => Warn
// c.GetLevel() => Warn
SyncParentLevel bool
// SubloggerHook registers a function that is called when a sublogger via
// Named, With, or ResetNamed is created. If defined, the function is passed
// the newly created Logger and the returned Logger is returned from the
// original function. This option allows customization via interception and
// wrapping of Logger instances.
SubloggerHook func(sub Logger) Logger
}
// InterceptLogger describes the interface for using a logger
// that can register different output sinks.
// This is useful for sending lower level log messages
// to a different output while keeping the root logger
// at a higher one.
type InterceptLogger interface {
// Logger is the root logger for an InterceptLogger
Logger
// RegisterSink adds a SinkAdapter to the InterceptLogger
RegisterSink(sink SinkAdapter)
// DeregisterSink removes a SinkAdapter from the InterceptLogger
DeregisterSink(sink SinkAdapter)
// Create a interceptlogger that will prepend the name string on the front of all messages.
// If the logger already has a name, the new value will be appended to the current
// name. That way, a major subsystem can use this to decorate all it's own logs
// without losing context.
NamedIntercept(name string) InterceptLogger
// Create a interceptlogger that will prepend the name string on the front of all messages.
// This sets the name of the logger to the value directly, unlike Named which honor
// the current name as well.
ResetNamedIntercept(name string) InterceptLogger
// Deprecated: use StandardLogger
StandardLoggerIntercept(opts *StandardLoggerOptions) *log.Logger
// Deprecated: use StandardWriter
StandardWriterIntercept(opts *StandardLoggerOptions) io.Writer
}
// SinkAdapter describes the interface that must be implemented
// in order to Register a new sink to an InterceptLogger
type SinkAdapter interface {
Accept(name string, level Level, msg string, args ...interface{})
}
// Flushable represents a method for flushing an output buffer. It can be used
// if Resetting the log to use a new output, in order to flush the writes to
// the existing output beforehand.
type Flushable interface {
Flush() error
}
// OutputResettable provides ways to swap the output in use at runtime
type OutputResettable interface {
// ResetOutput swaps the current output writer with the one given in the
// opts. Color options given in opts will be used for the new output.
ResetOutput(opts *LoggerOptions) error
// ResetOutputWithFlush swaps the current output writer with the one given
// in the opts, first calling Flush on the given Flushable. Color options
// given in opts will be used for the new output.
ResetOutputWithFlush(opts *LoggerOptions, flushable Flushable) error
}
// Locker is used for locking output. If not set when creating a logger, a
// sync.Mutex will be used internally.
type Locker interface {
// Lock is called when the output is going to be changed or written to
Lock()
// Unlock is called when the operation that called Lock() completes
Unlock()
}
// NoopLocker implements locker but does nothing. This is useful if the client
// wants tight control over locking, in order to provide grouping of log
// entries or other functionality.
type NoopLocker struct{}
// Lock does nothing
func (n NoopLocker) Lock() {}
// Unlock does nothing
func (n NoopLocker) Unlock() {}
var _ Locker = (*NoopLocker)(nil)

63
vendor/github.com/hashicorp/go-hclog/nulllogger.go generated vendored Normal file
View File

@@ -0,0 +1,63 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MIT
package hclog
import (
"io"
"io/ioutil"
"log"
)
// NewNullLogger instantiates a Logger for which all calls
// will succeed without doing anything.
// Useful for testing purposes.
func NewNullLogger() Logger {
return &nullLogger{}
}
type nullLogger struct{}
func (l *nullLogger) Log(level Level, msg string, args ...interface{}) {}
func (l *nullLogger) Trace(msg string, args ...interface{}) {}
func (l *nullLogger) Debug(msg string, args ...interface{}) {}
func (l *nullLogger) Info(msg string, args ...interface{}) {}
func (l *nullLogger) Warn(msg string, args ...interface{}) {}
func (l *nullLogger) Error(msg string, args ...interface{}) {}
func (l *nullLogger) IsTrace() bool { return false }
func (l *nullLogger) IsDebug() bool { return false }
func (l *nullLogger) IsInfo() bool { return false }
func (l *nullLogger) IsWarn() bool { return false }
func (l *nullLogger) IsError() bool { return false }
func (l *nullLogger) ImpliedArgs() []interface{} { return []interface{}{} }
func (l *nullLogger) With(args ...interface{}) Logger { return l }
func (l *nullLogger) Name() string { return "" }
func (l *nullLogger) Named(name string) Logger { return l }
func (l *nullLogger) ResetNamed(name string) Logger { return l }
func (l *nullLogger) SetLevel(level Level) {}
func (l *nullLogger) GetLevel() Level { return NoLevel }
func (l *nullLogger) StandardLogger(opts *StandardLoggerOptions) *log.Logger {
return log.New(l.StandardWriter(opts), "", log.LstdFlags)
}
func (l *nullLogger) StandardWriter(opts *StandardLoggerOptions) io.Writer {
return ioutil.Discard
}

Some files were not shown because too many files have changed in this diff Show More