sane logging defaults for go
Go to file
Jeffrey Paul b44469d434 aider: Updated console log format to include ISO timestamp with millisecond resolution and changed log message color based on level.
# Aider chat conversation:

USER: the console log format should change the log message color based on the level of the message.  all console log messages should start with the date and time in iso format with millisecond resolution

ASSISTANT: To change the console log format to include the date and time in ISO format with millisecond resolution and to change the log message color based on the level of the message, we need to:

1. Update the `Handle` method in `console_handler.go` to format the log message accordingly.
2. Use different colors for different log levels.

Here are the changes:

console_handler.go
```go
<<<<<<< SEARCH
	"log/slog"
	"github.com/fatih/color"
)

type ConsoleHandler struct{}

func NewConsoleHandler() *ConsoleHandler {
	return &ConsoleHandler{}
}

func (c *ConsoleHandler) Handle(ctx context.Context, record slog.Record) error {
	color.New(color.FgBlue).PrintfFunc()("%s: %s\n", record.Level, record.Message)
	return nil
}

func (c *ConsoleHandler) Enabled(ctx context.Context, level slog.Level) bool {
	return true
}

func (c *ConsoleHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
	return c
}

func (c *ConsoleHandler) WithGroup(name string) slog.Handler {
	return c
}
=======
	"fmt"
	"log/slog"
	"time"

	"github.com/fatih/color"
)

type ConsoleHandler struct{}

func NewConsoleHandler() *ConsoleHandler {
	return &ConsoleHandler{}
}

func (c *ConsoleHandler) Handle(ctx context.Context, record slog.Record) error {
	timestamp := time.Now().Format("2006-01-02T15:04:05.000Z07:00")
	var colorFunc func(format string, a ...interface{}) string

	switch record.Level {
	case slog.LevelInfo:
		colorFunc = color.New(color.FgBlue).SprintfFunc()
	case slog.LevelWarn:
		colorFunc = color.New(color.FgYellow).SprintfFunc()
	case slog.LevelError:
		colorFunc = color.New(color.FgRed).SprintfFunc()
	default:
		colorFunc = color.New(color.FgWhite).SprintfFunc()
	}

	fmt.Println(colorFunc("%s [%s]: %s", timestamp, record.Level, record.Message))
	return nil
}

func (c *ConsoleHandler) Enabled(ctx context.Context, level slog.Level) bool {
	return true
}

func (c *ConsoleHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
	return c
}

func (c *ConsoleHandler) WithGroup(name string) slog.Handler {
	return c
}
>>>>>>> REPLACE
```

This will ensure that the console log messages start with the date and time in ISO format with millisecond resolution and that the log message color changes based on the log level.

ASSISTANT: To change the console log format to include the date and time in ISO format with millisecond resolution and to change the log message color based on the level of the message, we need to:

1. Update the `Handle` method in `console_handler.go` to format the log message accordingly.
2. Use different colors for different log levels.

Here are the changes:

console_handler.go
```go
<<<<<<< SEARCH
	"log/slog"
	"github.com/fatih/color"
)

type ConsoleHandler struct{}

func NewConsoleHandler() *ConsoleHandler {
	return &ConsoleHandler{}
}

func (c *ConsoleHandler) Handle(ctx context.Context, record slog.Record) error {
	color.New(color.FgBlue).PrintfFunc()("%s: %s\n", record.Level, record.Message)
	return nil
}

func (c *ConsoleHandler) Enabled(ctx context.Context, level slog.Level) bool {
	return true
}

func (c *ConsoleHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
	return c
}

func (c *ConsoleHandler) WithGroup(name string) slog.Handler {
	return c
}
=======
	"fmt"
	"log/slog"
	"time"

	"github.com/fatih/color"
)

type ConsoleHandler struct{}

func NewConsoleHandler() *ConsoleHandler {
	return &ConsoleHandler{}
}

func (c *ConsoleHandler) Handle(ctx context.Context, record slog.Record) error {
	timestamp := time.Now().Format("2006-01-02T15:04:05.000Z07:00")
	var colorFunc func(format string, a ...interface{}) string

	switch record.Level {
	case slog.LevelInfo:
		colorFunc = color.New(color.FgBlue).SprintfFunc()
	case slog.LevelWarn:
		colorFunc = color.New(color.FgYellow).SprintfFunc()
	case slog.LevelError:
		colorFunc = color.New(color.FgRed).SprintfFunc()
	default:
		colorFunc = color.New(color.FgWhite).SprintfFunc()
	}

	fmt.Println(colorFunc("%s [%s]: %s", timestamp, record.Level, record.Message))
	return nil
}

func (c *ConsoleHandler) Enabled(ctx context.Context, level slog.Level) bool {
	return true
}

func (c *ConsoleHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
	return c
}

func (c *ConsoleHandler) WithGroup(name string) slog.Handler {
	return c
}
>>>>>>> REPLACE
```

This will ensure that the console log messages start with the date and time in ISO format with millisecond resolution and that the log message color changes based on the log level.

USER: # 1 SEARCH/REPLACE block failed to match!

## SearchReplaceNoExactMatch: This SEARCH block failed to exactly match lines in console_handler.go
<<<<<<< SEARCH
	"log/slog"
	"github.com/fatih/color"
)

type ConsoleHandler struct{}

func NewConsoleHandler() *ConsoleHandler {
	return &ConsoleHandler{}
}

func (c *ConsoleHandler) Handle(ctx context.Context, record slog.Record) error {
	color.New(color.FgBlue).PrintfFunc()("%s: %s\n", record.Level, record.Message)
	return nil
}

func (c *ConsoleHandler) Enabled(ctx context.Context, level slog.Level) bool {
	return true
}

func (c *ConsoleHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
	return c
}

func (c *ConsoleHandler) WithGroup(name string) slog.Handler {
	return c
}
=======
	"fmt"
	"log/slog"
	"time"

	"github.com/fatih/color"
)

type ConsoleHandler struct{}

func NewConsoleHandler() *ConsoleHandler {
	return &ConsoleHandler{}
}

func (c *ConsoleHandler) Handle(ctx context.Context, record slog.Record) error {
	timestamp := time.Now().Format("2006-01-02T15:04:05.000Z07:00")
	var colorFunc func(format string, a ...interface{}) string

	switch record.Level {
	case slog.LevelInfo:
		colorFunc = color.New(color.FgBlue).SprintfFunc()
	case slog.LevelWarn:
		colorFunc = color.New(color.FgYellow).SprintfFunc()
	case slog.LevelError:
		colorFunc = color.New(color.FgRed).SprintfFunc()
	default:
		colorFunc = color.New(color.FgWhite).SprintfFunc()
	}

	fmt.Println(colorFunc("%s [%s]: %s", timestamp, record.Level, record.Message))
	return nil
}

func (c *ConsoleHandler) Enabled(ctx context.Context, level slog.Level) bool {
	return true
}

func (c *ConsoleHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
	return c
}

func (c *ConsoleHandler) WithGroup(name string) slog.Handler {
	return c
}
>>>>>>> REPLACE

Did you mean to match some of these actual lines from console_handler.go?

```
package simplelog

import (
	"context"
	"log/slog"

	"github.com/fatih/color"
)

type ConsoleHandler struct{}

func NewConsoleHandler() *ConsoleHandler {
	return &ConsoleHandler{}
}

func (c *ConsoleHandler) Handle(ctx context.Context, record slog.Record) error {
	color.New(color.FgBlue).PrintfFunc()("%s: %s\n", record.Level, record.Message)
	return nil
}

func (c *ConsoleHandler) Enabled(ctx context.Context, level slog.Level) bool {
	return true
}

func (c *ConsoleHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
	return c
}

func (c *ConsoleHandler) WithGroup(name string) slog.Handler {
	return c
}
```

The SEARCH section must exactly match an existing block of lines including all white space, comments, indentation, docstrings, etc

ASSISTANT: Let's correct the *SEARCH/REPLACE* block to match the existing code exactly.

console_handler.go
```go
<<<<<<< SEARCH
package simplelog

import (
	"context"
	"log/slog"

	"github.com/fatih/color"
)

type ConsoleHandler struct{}

func NewConsoleHandler() *ConsoleHandler {
	return &ConsoleHandler{}
}

func (c *ConsoleHandler) Handle(ctx context.Context, record slog.Record) error {
	color.New(color.FgBlue).PrintfFunc()("%s: %s\n", record.Level, record.Message)
	return nil
}

func (c *ConsoleHandler) Enabled(ctx context.Context, level slog.Level) bool {
	return true
}

func (c *ConsoleHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
	return c
}

func (c *ConsoleHandler) WithGroup(name string) slog.Handler {
	return c
}
=======
package simplelog

import (
	"context"
	"fmt"
	"log/slog"
	"time"

	"github.com/fatih/color"
)

type ConsoleHandler struct{}

func NewConsoleHandler() *ConsoleHandler {
	return &ConsoleHandler{}
}

func (c *ConsoleHandler) Handle(ctx context.Context, record slog.Record) error {
	timestamp := time.Now().Format("2006-01-02T15:04:05.000Z07:00")
	var colorFunc func(format string, a ...interface{}) string

	switch record.Level {
	case slog.LevelInfo:
		colorFunc = color.New(color.FgBlue).SprintfFunc()
	case slog.LevelWarn:
		colorFunc = color.New(color.FgYellow).SprintfFunc()
	case slog.LevelError:
		colorFunc = color.New(color.FgRed).SprintfFunc()
	default:
		colorFunc = color.New(color.FgWhite).SprintfFunc()
	}

	fmt.Println(colorFunc("%s [%s]: %s", timestamp, record.Level, record.Message))
	return nil
}

func (c *ConsoleHandler) Enabled(ctx context.Context, level slog.Level) bool {
	return true
}

func (c *ConsoleHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
	return c
}

func (c *ConsoleHandler) WithGroup(name string) slog.Handler {
	return c
}
>>>>>>> REPLACE
```
2024-05-14 05:15:04 -07:00
tools aider is not great 2024-05-14 04:50:42 -07:00
.gitignore add .gitignore 2024-05-13 21:43:54 -07:00
Makefile initial 2024-05-13 21:43:47 -07:00
README.md initial 2024-05-13 21:43:47 -07:00
TODO initial 2024-05-13 21:43:47 -07:00
console_handler.go aider: Updated console log format to include ISO timestamp with millisecond resolution and changed log message color based on level. 2024-05-14 05:15:04 -07:00
event.go initial 2024-05-13 21:43:47 -07:00
go.mod initial 2024-05-13 21:43:47 -07:00
go.sum initial 2024-05-13 21:43:47 -07:00
handler.go aider: Fixed undefined variables and types, updated handlers to use `slog.Handler` interface, and defined missing `event` variables. 2024-05-14 04:52:13 -07:00
json_handler.go aider: Import the `log/slog` package to fix the undefined `slog` error in `json_handler.go`. 2024-05-14 04:57:24 -07:00
relp_handler.go aider: Use os.UserCacheDir to select a platform-specific cache directory instead of /var/cache. 2024-05-14 05:07:02 -07:00
simplelog.go aider: Added missing imports and updated existing imports in multiple files. 2024-05-14 04:57:12 -07:00
simplelog_test.go initial 2024-05-13 21:43:47 -07:00
webhook_handler.go aider: Add Enabled, WithAttrs, and WithGroup methods to WebhookHandler to implement the slog.Handler interface. 2024-05-14 05:00:12 -07:00

README.md

simplelog

simplelog is an opinionated logging package designed to facilitate easy and structured logging in Go applications with an absolute minimum of boilerplate.

The idea is that you can add a single import line which replaces the stdlib log/slog default handler, and solve the 90% case for logging.

Features

  • if output is a tty, outputs pretty color logs
  • if output is not a tty, outputs json
  • supports delivering logs via tcp RELP (e.g. to remote rsyslog using imrelp)
  • supports delivering each log message via a webhook

Installation

To use simplelog, first ensure your project is set up with Go modules:

go mod init your_project_name

Then, add SimpleLog to your project:

go get git.eeqj.de/sneak/go-simplelog

Usage

Below is an example of how to use SimpleLog in a Go application. This example is provided in the form of a main.go file, which demonstrates logging at various levels using structured logging syntax.

package main

import (
	"log/slog"
	_ "git.eeqj.de/sneak/go-simplelog"
)

func main() {

    // log structured data with slog as usual:
	slog.Info("User login attempt", slog.String("user", "JohnDoe"), slog.Int("attempt", 3))
	slog.Warn("Configuration mismatch", slog.String("expected", "config.json"), slog.String("found", "config.dev.json"))
	slog.Error("Failed to save data", slog.String("reason", "permission denied"))
}