π¨ slog: Parquet handler + Object Storage
See the codeA parquet Handler for slog Go library.
See also:
slog.Handler chaining, fanout, routing, failover, load balancing...slog attribute formattingslog sampling policyslog.Handler for test purposesHTTP middlewares:
slog loggerslog loggerslog loggerslog loggernet/http middleware for slog loggerLoggers:
slog handler for Zapslog handler for Zerologslog handler for LogrusLog sinks:
slog handler for Datadogslog handler for Betterstackslog handler for Rollbarslog handler for Lokislog handler for Sentryslog handler for Syslogslog handler for Logstashslog handler for Fluentdslog handler for Graylogslog handler for Quickwitslog handler for Slackslog handler for Telegramslog handler for Mattermostslog handler for Microsoft Teamsslog handler for Webhookslog handler for Kafkaslog handler for NATSslog handler for Parquet + Object Storageslog handler for Go channelsgo get github.com/samber/slog-parquet/v2
Compatibility: go >= 1.21
No breaking changes will be made to exported APIs before v3.0.0.
GoDoc: https://pkg.go.dev/github.com/samber/slog-parquet/v2
type Option struct {
// log level (default: debug)
Level slog.Leveler
// parquet rows buffer
Buffer slogparquet.ParquetBuffer
// optional: customize json payload builder
Converter Converter
// optional: fetch attributes from context
AttrFromContext []func(ctx context.Context) []slog.Attr
// optional: see slog.HandlerOptions
AddSource bool
ReplaceAttr func(groups []string, a slog.Attr) slog.Attr
}
Other global parameters:
slogparquet.SourceKey = "source"
slogparquet.ErrorKeys = []string{"error", "err"}
func NewParquetBuffer(bucket objstore.Bucket, prefix string, maxRecords int, maxInterval time.Duration) slogparquet.ParquetBuffer
Attributes will be injected in log payload.
See github.com/thanos-io/objstore.
import (
"log/slog"
slogparquet "github.com/samber/slog-parquet/v2"
"github.com/thanos-io/objstore/providers/s3"
)
func main() {
bucket, _ := s3.NewBucketWithConfig(
slogparquet.NewLogger(),
s3.Config{
Endpoint: os.Getenv("AWS_S3_ENDPOINT"),
Region: os.Getenv("AWS_S3_REGION"),
Bucket: os.Getenv("AWS_S3_BUCKET"),
AccessKey: os.Getenv("AWS_ACCESS_KEY"),
SecretKey: os.Getenv("AWS_SECRET_KEY"),
PartSize: 16 * 1024 * 1024, // 16MB
},
"logger",
)
buffer := slogparquet.NewParquetBuffer(bucket, "api/logs", 10*1024*1024)
logger := slog.New(slogparquet.Option{Level: slog.LevelDebug, Buffer: buffer}.NewParquetHandler())
logger = logger.
With("environment", "dev").
With("release", "v1.0.0")
// log error
logger.
With("category", "sql").
With("query.statement", "SELECT COUNT(*) FROM users;").
With("query.duration", 1*time.Second).
With("error", fmt.Errorf("could not count users")).
Error("caramba!")
// log user signup
logger.
With(
slog.Group("user",
slog.String("id", "user-123"),
slog.Time("created_at", time.Now()),
),
).
Info("user registration")
buffer.Flush(true)
bucket.Close()
}
Output:
$ parquet meta ~/Downloads/00_17_08.d4d9f.parquet
File path: /Users/samber/Downloads/00_17_08.d4d9f.parquet
Created by: github.com/samber/slog-parquet version (devel)(build )
Properties: (none)
Schema:
message log {
required int64 time (TIMESTAMP(NANOS,true));
required binary log_level (STRING);
required binary message (STRING);
required binary attributes;
required binary source (STRING);
}
Row group 0: count: 2 279.00 B records start: 51 total(compressed): 558 B total(uncompressed):644 B
--------------------------------------------------------------------------------
type encodings count avg size nulls min / max
time INT64 F _ 2 22.50 B "2023-08-19T00:17:08.14408..." / "2023-08-19T00:17:08.14420..."
log_level BINARY F 2 26.50 B "ERROR" / "INFO"
message BINARY F 2 35.00 B "caramba!" / "user registration"
attributes BINARY F 2 155.50 B "0x7B2263617465676F7279223..." / "0x7B22656E7669726F6E6D656..."
source BINARY F 2 39.50 B "samber/slog-parquet" / "samber/slog-parquet"
Import the samber/slog-otel library.
import (
slogparquet "github.com/samber/slog-parquet"
slogotel "github.com/samber/slog-otel"
"go.opentelemetry.io/otel/sdk/trace"
)
func main() {
tp := trace.NewTracerProvider(
trace.WithSampler(trace.AlwaysSample()),
)
tracer := tp.Tracer("hello/world")
ctx, span := tracer.Start(context.Background(), "foo")
defer span.End()
span.AddEvent("bar")
logger := slog.New(
slogparquet.Option{
// ...
AttrFromContext: []func(ctx context.Context) []slog.Attr{
slogotel.ExtractOtelAttrFromContext([]string{"tracing"}, "trace_id", "span_id"),
},
}.NewParquetHandler(),
)
logger.ErrorContext(ctx, "a message")
}
Don't hesitate ;)
# Install some dev dependencies
make tools
# Run tests
make test
# or
make watch-test
Give a βοΈ if this project helped you!
Copyright Β© 2023 Samuel Berthe.
This project is MIT licensed.
Go
90.0%
Makefile
10.0%
π¨ slog: Parquet handler + Object Storage
See the codeA parquet Handler for slog Go library.
See also:
slog.Handler chaining, fanout, routing, failover, load balancing...slog attribute formattingslog sampling policyslog.Handler for test purposesHTTP middlewares:
slog loggerslog loggerslog loggerslog loggernet/http middleware for slog loggerLoggers:
slog handler for Zapslog handler for Zerologslog handler for LogrusLog sinks:
slog handler for Datadogslog handler for Betterstackslog handler for Rollbarslog handler for Lokislog handler for Sentryslog handler for Syslogslog handler for Logstashslog handler for Fluentdslog handler for Graylogslog handler for Quickwitslog handler for Slackslog handler for Telegramslog handler for Mattermostslog handler for Microsoft Teamsslog handler for Webhookslog handler for Kafkaslog handler for NATSslog handler for Parquet + Object Storageslog handler for Go channelsgo get github.com/samber/slog-parquet/v2
Compatibility: go >= 1.21
No breaking changes will be made to exported APIs before v3.0.0.
GoDoc: https://pkg.go.dev/github.com/samber/slog-parquet/v2
type Option struct {
// log level (default: debug)
Level slog.Leveler
// parquet rows buffer
Buffer slogparquet.ParquetBuffer
// optional: customize json payload builder
Converter Converter
// optional: fetch attributes from context
AttrFromContext []func(ctx context.Context) []slog.Attr
// optional: see slog.HandlerOptions
AddSource bool
ReplaceAttr func(groups []string, a slog.Attr) slog.Attr
}
Other global parameters:
slogparquet.SourceKey = "source"
slogparquet.ErrorKeys = []string{"error", "err"}
func NewParquetBuffer(bucket objstore.Bucket, prefix string, maxRecords int, maxInterval time.Duration) slogparquet.ParquetBuffer
Attributes will be injected in log payload.
See github.com/thanos-io/objstore.
import (
"log/slog"
slogparquet "github.com/samber/slog-parquet/v2"
"github.com/thanos-io/objstore/providers/s3"
)
func main() {
bucket, _ := s3.NewBucketWithConfig(
slogparquet.NewLogger(),
s3.Config{
Endpoint: os.Getenv("AWS_S3_ENDPOINT"),
Region: os.Getenv("AWS_S3_REGION"),
Bucket: os.Getenv("AWS_S3_BUCKET"),
AccessKey: os.Getenv("AWS_ACCESS_KEY"),
SecretKey: os.Getenv("AWS_SECRET_KEY"),
PartSize: 16 * 1024 * 1024, // 16MB
},
"logger",
)
buffer := slogparquet.NewParquetBuffer(bucket, "api/logs", 10*1024*1024)
logger := slog.New(slogparquet.Option{Level: slog.LevelDebug, Buffer: buffer}.NewParquetHandler())
logger = logger.
With("environment", "dev").
With("release", "v1.0.0")
// log error
logger.
With("category", "sql").
With("query.statement", "SELECT COUNT(*) FROM users;").
With("query.duration", 1*time.Second).
With("error", fmt.Errorf("could not count users")).
Error("caramba!")
// log user signup
logger.
With(
slog.Group("user",
slog.String("id", "user-123"),
slog.Time("created_at", time.Now()),
),
).
Info("user registration")
buffer.Flush(true)
bucket.Close()
}
Output:
$ parquet meta ~/Downloads/00_17_08.d4d9f.parquet
File path: /Users/samber/Downloads/00_17_08.d4d9f.parquet
Created by: github.com/samber/slog-parquet version (devel)(build )
Properties: (none)
Schema:
message log {
required int64 time (TIMESTAMP(NANOS,true));
required binary log_level (STRING);
required binary message (STRING);
required binary attributes;
required binary source (STRING);
}
Row group 0: count: 2 279.00 B records start: 51 total(compressed): 558 B total(uncompressed):644 B
--------------------------------------------------------------------------------
type encodings count avg size nulls min / max
time INT64 F _ 2 22.50 B "2023-08-19T00:17:08.14408..." / "2023-08-19T00:17:08.14420..."
log_level BINARY F 2 26.50 B "ERROR" / "INFO"
message BINARY F 2 35.00 B "caramba!" / "user registration"
attributes BINARY F 2 155.50 B "0x7B2263617465676F7279223..." / "0x7B22656E7669726F6E6D656..."
source BINARY F 2 39.50 B "samber/slog-parquet" / "samber/slog-parquet"
Import the samber/slog-otel library.
import (
slogparquet "github.com/samber/slog-parquet"
slogotel "github.com/samber/slog-otel"
"go.opentelemetry.io/otel/sdk/trace"
)
func main() {
tp := trace.NewTracerProvider(
trace.WithSampler(trace.AlwaysSample()),
)
tracer := tp.Tracer("hello/world")
ctx, span := tracer.Start(context.Background(), "foo")
defer span.End()
span.AddEvent("bar")
logger := slog.New(
slogparquet.Option{
// ...
AttrFromContext: []func(ctx context.Context) []slog.Attr{
slogotel.ExtractOtelAttrFromContext([]string{"tracing"}, "trace_id", "span_id"),
},
}.NewParquetHandler(),
)
logger.ErrorContext(ctx, "a message")
}
Don't hesitate ;)
# Install some dev dependencies
make tools
# Run tests
make test
# or
make watch-test
Give a βοΈ if this project helped you!
Copyright Β© 2023 Samuel Berthe.
This project is MIT licensed.
Go
90.0%
Makefile
10.0%