Skip to content

Commit

Permalink
add support for log/slog std package
Browse files Browse the repository at this point in the history
  • Loading branch information
kataras committed Nov 1, 2023
1 parent fa0b1af commit ec2064d
Show file tree
Hide file tree
Showing 11 changed files with 199 additions and 77 deletions.
17 changes: 11 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ on:
pull_request:
branches: [master]

permissions:
contents: read

jobs:

test:
Expand All @@ -14,16 +17,18 @@ jobs:

strategy:
matrix:
go_version: [1.19.x]
go_version: [1.21.x]
steps:

- name: Check out code into the Go module directory
uses: actions/checkout@v4

- name: Set up Go 1.x
uses: actions/setup-go@v2
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go_version }}

- name: Check out code into the Go module directory
uses: actions/checkout@v2
go-version-file: './go.mod'
check-latest: true
- run: go version

- name: Test
run: go test -v ./...
Expand Down
14 changes: 14 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
## Wed 11 November 2023 | v0.1.11

- Add integration for `"log/slog"` package:

```go
import "log/slog"

// [...]
myLogger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
golog.Install(myLogger) // OR just golog.Install(slog.Default())
```

- The `InstallStd` method was removed, use the `Install` method instead, it receives `any` instead of just `ExternalLogger` now.

## Sat 29 October 2022 | v0.1.8

Add `golog.Now` variable so 3rd-parties can customize the time.Now functionality used in golog.Log.Time and Timestamp.
Expand Down
55 changes: 38 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ Or edit your project's go.mod file and execute $ go build.
```mod
module your_project_name
go 1.19
go 1.21
require (
github.com/kataras/golog v0.1.8
github.com/kataras/golog v0.1.11
)
```

Expand Down Expand Up @@ -79,6 +79,9 @@ func main() {
golog.Debug("This is a debug message")
golog.Fatal(`Fatal will exit no matter what,
but it will also print the log message if logger's Level is >=FatalLevel`)

// Use any other supported logger through golog, e.g. the new "log/slog":
// golog.Install(slog.Default())
}
```

Expand Down Expand Up @@ -154,39 +157,57 @@ db, err := badger.Open(opts)

### Level-based and standard Loggers

You can put `golog` in front of your existing loggers using the [Install](https://pkg.go.dev/github.com/kataras/golog?tab=doc#Logger.Install) and [InstallStd](https://pkg.go.dev/github.com/kataras/golog?tab=doc#InstallStd) methods.
You can put `golog` in front of your existing loggers using the [Install](https://pkg.go.dev/github.com/kataras/golog?tab=doc#Logger.Install) method.

Supporte loggers:

Any level-based Logger that implements the [ExternalLogger](https://pkg.go.dev/github.com/kataras/golog?tab=doc#ExternalLogger) can be adapted.
- log
- slog
- logrus

E.g. [sirupsen/logrus](https://github.com/sirupsen/logrus):
Example for `log/slog` standard package:

```go
// Simulate a logrus logger preparation.
logrus.SetLevel(logrus.InfoLevel)
logrus.SetFormatter(&logrus.JSONFormatter{})
// Simulate an slog.Logger preparation.
var myLogger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug,
}))

golog.Install(logrus.StandardLogger())
func main() {
golog.SetLevel("error")
golog.Install(myLogger)

golog.Debug(`this debug message will not be shown,
because the logrus level is InfoLevel`)
golog.Error(`this error message will be visible as JSON,
because of logrus.JSONFormatter`)
golog.Error("error message")
}
```

Any standard logger (without level capabilities) that implements the [StdLogger](https://pkg.go.dev/github.com/kataras/golog?tab=doc#StdLogger) can be adapted using the [InstallStd](https://pkg.go.dev/github.com/kataras/golog?tab=doc#InstallStd) method.

E.g. `log` standard package:
Example for `log` standard package:

```go
// Simulate a log.Logger preparation.
myLogger := log.New(os.Stdout, "", 0)

golog.SetLevel("error")
golog.InstallStd(myLogger)
golog.Install(myLogger)

golog.Error("error message")
```

Example for [sirupsen/logrus](https://github.com/sirupsen/logrus):

```go
// Simulate a logrus logger preparation.
logrus.SetLevel(logrus.InfoLevel)
logrus.SetFormatter(&logrus.JSONFormatter{})

golog.Install(logrus.StandardLogger())

golog.Debug(`this debug message will not be shown,
because the logrus level is InfoLevel`)
golog.Error(`this error message will be visible as JSON,
because of logrus.JSONFormatter`)
```

## Output Format

Any value that completes the [Formatter interface](https://github.com/kataras/golog/blob/master/formatter.go) can be used to write to the (leveled) output writer. By default the `"json"` formatter is available.
Expand Down
23 changes: 23 additions & 0 deletions _examples/integrations/slog/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package main

import (
"log/slog"
"os"

"github.com/kataras/golog"
)

// simulate an slog.Logger preparation:
var myLogger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}))

func main() {
golog.SetLevel("error")
golog.Install(myLogger)

golog.Debug(`this debug message will not be shown,
because the golog level is ErrorLevel`)

golog.Error("this error message will be visible the only visible")

golog.Warn("this info message will not be visible")
}
2 changes: 1 addition & 1 deletion _examples/integrations/std/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var myLogger = log.New(os.Stdout, "", 0)

func main() {
golog.SetLevel("error")
golog.InstallStd(myLogger)
golog.Install(myLogger)

golog.Debug(`this debug message will not be shown,
because the golog level is ErrorLevel`)
Expand Down
29 changes: 14 additions & 15 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Source code and other details for the project are available at GitHub:
# Current Version
0.1.8
0.1.11
# Installation
Expand Down Expand Up @@ -266,24 +266,23 @@ Outline:
//
// For example, if you want to print using a logrus
// logger you can do the following:
// `golog.Install(logrus.StandardLogger())`
//
// Look `golog#Handle` for more.
Install(logger ExternalLogger)
// InstallStd receives a standard logger
// and automatically adapts its print functions.
// Install(logrus.StandardLogger())
//
// Install adds a golog handler to support third-party integrations,
// it can be used only once per `golog#Logger` instance.
// Or the standard log's Logger:
//
// Example Code:
// import "log"
// myLogger := log.New(os.Stdout, "", 0)
// InstallStd(myLogger)
// Install(myLogger)
//
// Or even the slog/log's Logger:
//
// Look `golog#Handle` for more.
InstallStd(logger StdLogger)
// import "log/slog"
// myLogger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
// Install(myLogger) OR Install(slog.Default())
//
// Look `golog#Logger.Handle` for more.
Install(logger ExternalLogger)
# Logrus Integration
Expand Down Expand Up @@ -350,7 +349,7 @@ Example Code:
func main() {
golog.SetLevel("error")
golog.InstallStd(myLogger)
golog.Install(myLogger)
golog.Debug(`this debug message will not be shown,
because the golog level is ErrorLevel`)
Expand All @@ -372,4 +371,4 @@ Examples:
package golog

// Version is the version string representation of the "golog" package.
const Version = "0.1.8"
const Version = "0.1.11"
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module github.com/kataras/golog

go 1.20
go 1.21

require github.com/kataras/pio v0.0.12
require github.com/kataras/pio v0.0.13

require golang.org/x/sys v0.9.0 // indirect
require golang.org/x/sys v0.13.0 // indirect
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
github.com/kataras/pio v0.0.12 h1:o52SfVYauS3J5X08fNjlGS5arXHjW/ItLkyLcKjoH6w=
github.com/kataras/pio v0.0.12/go.mod h1:ODK/8XBhhQ5WqrAhKy+9lTPS7sBf6O3KcLhc9klfRcY=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
github.com/kataras/pio v0.0.13 h1:x0rXVX0fviDTXOOLOmr4MUxOabu1InVSTu5itF8CXCM=
github.com/kataras/pio v0.0.13/go.mod h1:k3HNuSw+eJ8Pm2lA4lRhg3DiCjVgHlP8hmXApSej3oM=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
28 changes: 12 additions & 16 deletions golog.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,28 +191,24 @@ func Debugf(format string, args ...interface{}) {
//
// For example, if you want to print using a logrus
// logger you can do the following:
// `golog.Install(logrus.StandardLogger())`
//
// Look `golog#Handle` for more.
func Install(logger ExternalLogger) {
Default.Install(logger)
}

// InstallStd receives a standard logger
// and automatically adapts its print functions.
//
// Install adds a golog handler to support third-party integrations,
// it can be used only once per `golog#Logger` instance.
// Install(logrus.StandardLogger())
//
// Example Code:
// Or the standard log's Logger:
//
// import "log"
// myLogger := log.New(os.Stdout, "", 0)
// InstallStd(myLogger)
// Install(myLogger)
//
// Or even the slog/log's Logger:
//
// Look `golog#Handle` for more.
func InstallStd(logger StdLogger) {
Default.InstallStd(logger)
// import "log/slog"
// myLogger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
// Install(myLogger) OR Install(slog.Default())
//
// Look `golog#Logger.Handle` for more.
func Install(logger any) {
Default.Install(logger)
}

// Handle adds a log handler to the default logger.
Expand Down
68 changes: 68 additions & 0 deletions integration.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,59 @@
package golog

import (
"context"
"log/slog"
)

func integrade(logger any) Handler {
switch v := logger.(type) {
case *slog.Logger:
return integradeSlog(v)
case ExternalLogger:
return integrateExternalLogger(v)
case StdLogger:
return integrateStdLogger(v)
default:
panic("not supported logger integration, please open a feature request at: https://github.com/kataras/golog/issues/new")
}
}

/*
func (*slog.Logger).Debug(msg string, args ...any)
func (*slog.Logger).DebugContext(ctx context.Context, msg string, args ...any)
func (*slog.Logger).Enabled(ctx context.Context, level slog.Level) bool
func (*slog.Logger).Error(msg string, args ...any)
func (*slog.Logger).ErrorContext(ctx context.Context, msg string, args ...any)
func (*slog.Logger).Handler() slog.Handler
func (*slog.Logger).Info(msg string, args ...any)
func (*slog.Logger).InfoContext(ctx context.Context, msg string, args ...any)
func (*slog.Logger).Log(ctx context.Context, level slog.Level, msg string, args ...any)
func (*slog.Logger).LogAttrs(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr)
func (*slog.Logger).Warn(msg string, args ...any)
func (*slog.Logger).WarnContext(ctx context.Context, msg string, args ...any)
func (*slog.Logger).With(args ...any) *slog.Logger
func (*slog.Logger).WithGroup(name string) *slog.Logger
*/
func integradeSlog(logger *slog.Logger) Handler {
return func(log *Log) bool {
// golog level to slog level.
level := getSlogLevel(log.Level)
// golog fields to slog attributes.
if len(log.Fields) > 0 {
attrs := make([]slog.Attr, 0, len(log.Fields))
for k, v := range log.Fields {
attrs = append(attrs, slog.Any(k, v))
}
// log the message with attrs.
logger.LogAttrs(context.Background(), level, log.Message, attrs...)
} else {
logger.Log(context.Background(), level, log.Message)
}

return true
}
}

// ExternalLogger is a typical logger interface.
// Any logger or printer that completes this interface
// can be used to intercept and handle the golog's messages.
Expand Down Expand Up @@ -30,6 +84,20 @@ func integrateExternalLogger(logger ExternalLogger) Handler {
}
}

func getSlogLevel(level Level) slog.Level {
switch level {
case ErrorLevel:
return slog.LevelError
case WarnLevel:
return slog.LevelWarn
case InfoLevel:
return slog.LevelInfo
case DebugLevel:
return slog.LevelDebug
}
return slog.LevelDebug
}

func getExternalPrintFunc(logger ExternalLogger, log *Log) func(...interface{}) {
switch log.Level {
case ErrorLevel:
Expand Down
Loading

0 comments on commit ec2064d

Please sign in to comment.