Skip to content

Commit

Permalink
feat: Add Axiom handler for xlog and update related components
Browse files Browse the repository at this point in the history
- Implement AxiomHandler in xlog_handlers/axiom_handler.go
- Update xlog/xlog.go to support Axiom integration
- Modify xhttpc/xhttpc.go for improved HTTP client functionality
- Enhance examples/xlog_example/main.go with Axiom logging example
- Update .gitignore to exclude Axiom-related configuration files
  • Loading branch information
seefs001 committed Sep 27, 2024
1 parent ea4a935 commit b5e748f
Show file tree
Hide file tree
Showing 5 changed files with 304 additions and 47 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ go.work.sum
.env
.log
.idea/
.vscode/
.vscode/
app.*
39 changes: 37 additions & 2 deletions examples/xlog_example/main.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
package main

import (
"os"
"time"

"github.com/seefs001/xox/xenv"
"github.com/seefs001/xox/xhttpc"
"github.com/seefs001/xox/xlog"
"github.com/seefs001/xox/xlog_handlers"
)

func main() {
xenv.Load()

// Use the default console logger
xlog.Info("This is an info message")
xlog.Warn("This is a warning message")
Expand All @@ -21,12 +29,39 @@ func main() {
xlog.Error("Failed to add file logger", "error", err)
}

// Now logs will be output to both console and file without duplication
xlog.Info("This message will be logged to both console and file")
// Add Axiom handler if environment variables are set
axiomApiToken := os.Getenv("AXIOM_API_TOKEN")
axiomDataset := os.Getenv("AXIOM_DATASET")
if axiomApiToken != "" && axiomDataset != "" {
xlog.Info("Axiom handler adding")
axiomHandler := xlog_handlers.NewAxiomHandler(axiomApiToken, axiomDataset)

// Enable debug mode for Axiom handler
axiomHandler.SetDebug(true)
axiomHandler.SetLogOptions(xhttpc.LogOptions{
LogHeaders: true,
LogBody: true,
LogResponse: true,
MaxBodyLogSize: 1024,
HeaderKeysToLog: []string{"Content-Type", "Authorization"},
})

xlog.Add(axiomHandler)
xlog.Info("Axiom handler added")
}

// Now logs will be output to console, file, and Axiom (if configured)
xlog.Info("This message will be logged to all configured handlers")

// Use the Catch function to wrap operations that may produce errors
xlog.Catch(func() error {
// Simulate an operation that may produce an error
return nil // or return an error
})

// Add a small delay to allow logs to be sent
time.Sleep(2 * time.Second)

// Gracefully shutdown all handlers
xlog.Shutdown()
}
19 changes: 19 additions & 0 deletions xhttpc/xhttpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,11 @@ func WithLogOptions(options LogOptions) ClientOption {
}
}

// SetLogOptions sets the logging options for debug mode
func (c *Client) SetLogOptions(options LogOptions) {
c.logOptions = options
}

// SetBaseURL sets the base URL for all requests
func (c *Client) SetBaseURL(url string) *Client {
c.baseURL = url
Expand Down Expand Up @@ -647,3 +652,17 @@ func basicAuth(username, password string) string {
auth := username + ":" + password
return base64.StdEncoding.EncodeToString([]byte(auth))
}

// WithBearerToken sets bearer auth token for all requests
func WithBearerToken(token string) ClientOption {
return func(c *Client) {
c.SetBearerToken(token)
}
}

// WithBaseURL sets the base URL for all requests
func WithBaseURL(url string) ClientOption {
return func(c *Client) {
c.SetBaseURL(url)
}
}
110 changes: 66 additions & 44 deletions xlog/xlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ var (
defaultHandler slog.Handler
logConfig LogConfig
defaultLevel slog.Level
handlers []slog.Handler // Add this line
)

// LogConfig represents the configuration for logging.
Expand Down Expand Up @@ -200,12 +201,67 @@ func (h *ColorConsoleHandler) WithGroup(name string) slog.Handler {
return &newHandler
}

// Add replaces the current handler with a new one
// Add adds a new handler to the existing handlers
func Add(handler slog.Handler) {
defaultHandler = handler
handlers = append(handlers, handler) // Update this line
if mh, ok := defaultHandler.(*MultiHandler); ok {
// If defaultHandler is already a MultiHandler, add the new handler to it
mh.handlers = append(mh.handlers, handler)
} else {
// If not, create a new MultiHandler with both handlers
defaultHandler = NewMultiHandler(defaultHandler, handler)
}
defaultLogger = slog.New(defaultHandler)
}

// NewMultiHandler creates a new MultiHandler
func NewMultiHandler(handlers ...slog.Handler) *MultiHandler {
return &MultiHandler{handlers: handlers}
}

// MultiHandler implements a handler that writes to multiple handlers
type MultiHandler struct {
handlers []slog.Handler
}

// Enabled implements the Handler interface
func (h *MultiHandler) Enabled(ctx context.Context, level slog.Level) bool {
for _, handler := range h.handlers {
if handler.Enabled(ctx, level) {
return true
}
}
return false
}

// Handle implements the Handler interface
func (h *MultiHandler) Handle(ctx context.Context, r slog.Record) error {
for _, handler := range h.handlers {
if err := handler.Handle(ctx, r); err != nil {
return err
}
}
return nil
}

// WithAttrs implements the Handler interface
func (h *MultiHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
handlers := make([]slog.Handler, len(h.handlers))
for i, handler := range h.handlers {
handlers[i] = handler.WithAttrs(attrs)
}
return NewMultiHandler(handlers...)
}

// WithGroup implements the Handler interface
func (h *MultiHandler) WithGroup(name string) slog.Handler {
handlers := make([]slog.Handler, len(h.handlers))
for i, handler := range h.handlers {
handlers[i] = handler.WithGroup(name)
}
return NewMultiHandler(handlers...)
}

// FileConfig represents the configuration for file logging.
type FileConfig struct {
Filename string
Expand Down Expand Up @@ -330,50 +386,16 @@ func Catch(f func() error) {
}
}

// MultiHandler implements a multi-handler that writes to multiple handlers.
type MultiHandler struct {
handlers []slog.Handler
// Add this interface if it doesn't exist
type ShutdownHandler interface {
Shutdown()
}

// NewMultiHandler creates a new MultiHandler.
func NewMultiHandler(handlers ...slog.Handler) *MultiHandler {
return &MultiHandler{handlers: handlers}
}

// Enabled implements the slog.Handler interface.
func (h *MultiHandler) Enabled(ctx context.Context, level slog.Level) bool {
for _, handler := range h.handlers {
if handler.Enabled(ctx, level) {
return true
// Add a function to shutdown all handlers
func Shutdown() {
for _, handler := range handlers {
if sh, ok := handler.(ShutdownHandler); ok {
sh.Shutdown()
}
}
return false
}

// Handle implements the slog.Handler interface.
func (h *MultiHandler) Handle(ctx context.Context, r slog.Record) error {
for _, handler := range h.handlers {
if err := handler.Handle(ctx, r); err != nil {
return err
}
}
return nil
}

// WithAttrs implements the slog.Handler interface.
func (h *MultiHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
handlers := make([]slog.Handler, len(h.handlers))
for i, handler := range h.handlers {
handlers[i] = handler.WithAttrs(attrs)
}
return NewMultiHandler(handlers...)
}

// WithGroup implements the slog.Handler interface.
func (h *MultiHandler) WithGroup(name string) slog.Handler {
handlers := make([]slog.Handler, len(h.handlers))
for i, handler := range h.handlers {
handlers[i] = handler.WithGroup(name)
}
return NewMultiHandler(handlers...)
}
Loading

0 comments on commit b5e748f

Please sign in to comment.