Files
Asim Aslam c7657f73f4
goreleaser / goreleaser (push) Has been cancelled
Refactor agent plan storage, update docs, and release v6 (#2977)
* test(harness): read agent plan from the scoped store

The store-scoping change moved an agent's plan from the default table
key agent/{name}/plan to its own table (database "agent", table {name},
key "plan"). The plan-delegate harness tests still read the old key and
failed with 'not found'; read through store.Scope(mem, "agent", name)
like the agent does.

* docs: orient agents-first across README, landing, and docs overview

Lead with agents (then services and flows), surface MCP + A2A as the
interop story, and frame agents as services. Landing hero and feature
grid reordered agents-first with an A2A gateway card.

* v6: module path go-micro.dev/v6, TLS secure by default, NewService

Cut v6. Three breaking changes, bundled so the major bump is paid once:

- Module path go-micro.dev/v5 -> go-micro.dev/v6 across all imports + go.mod.
- TLS verification on by default (was off). MICRO_TLS_SECURE removed;
  MICRO_TLS_INSECURE=true opts out for self-signed/dev.
- micro.NewService(name, opts...) is the canonical service constructor,
  symmetric with NewAgent/NewFlow; micro.New kept as a deprecated alias;
  the old name-less NewService(opts...) removed. Generators emit NewService.

Also ports the JWT auth token provider in-module (go-micro.dev/v6/auth/jwt/token
on golang-jwt/jwt/v5), dropping the v5-pinned github.com/micro/plugins/v5/auth/jwt
and the deprecated dgrijalva/jwt-go.

Docs/README/landing updated to v6 and @latest; v5->v6 migration guide added;
CHANGELOG cut as [6.0.0]. Blog posts left at their historical versions.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-18 11:55:35 +01:00

163 lines
3.6 KiB
Go

package logger
import (
"context"
"fmt"
"log/slog"
"runtime"
"strings"
dlog "go-micro.dev/v6/debug/log"
)
// debugLogHandler is a slog handler that writes to the debug/log buffer
type debugLogHandler struct {
level slog.Leveler
attrs []slog.Attr
group string
}
// newDebugLogHandler creates a new handler that writes to debug/log
func newDebugLogHandler(level slog.Leveler) *debugLogHandler {
return &debugLogHandler{
level: level,
attrs: make([]slog.Attr, 0),
}
}
func (h *debugLogHandler) Enabled(_ context.Context, level slog.Level) bool {
return level >= h.level.Level()
}
func (h *debugLogHandler) Handle(_ context.Context, r slog.Record) error {
// Build metadata from attributes
metadata := make(map[string]string)
// Add handler's attributes
for _, attr := range h.attrs {
metadata[attr.Key] = attr.Value.String()
}
// Add record's attributes
r.Attrs(func(a slog.Attr) bool {
metadata[a.Key] = a.Value.String()
return true
})
// Add level to metadata
metadata["level"] = r.Level.String()
// Add source if available
if sourcePath := extractSourceFilePath(r.PC); sourcePath != "" {
metadata["file"] = sourcePath
}
// Create debug log record
rec := dlog.Record{
Timestamp: r.Time,
Message: r.Message,
Metadata: metadata,
}
// Write to debug log
_ = dlog.DefaultLog.Write(rec)
return nil
}
func (h *debugLogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
newAttrs := make([]slog.Attr, len(h.attrs)+len(attrs))
copy(newAttrs, h.attrs)
copy(newAttrs[len(h.attrs):], attrs)
return &debugLogHandler{
level: h.level,
attrs: newAttrs,
group: h.group,
}
}
func (h *debugLogHandler) WithGroup(name string) slog.Handler {
// For simplicity, we'll just track the group name
// A full implementation would nest attributes properly
return &debugLogHandler{
level: h.level,
attrs: h.attrs,
group: name,
}
}
// multiHandler sends records to multiple handlers
type multiHandler struct {
handlers []slog.Handler
}
func newMultiHandler(handlers ...slog.Handler) *multiHandler {
return &multiHandler{
handlers: handlers,
}
}
func (h *multiHandler) Enabled(ctx context.Context, level slog.Level) bool {
// Enabled if any handler is enabled
for _, handler := range h.handlers {
if handler.Enabled(ctx, level) {
return true
}
}
return false
}
func (h *multiHandler) Handle(ctx context.Context, r slog.Record) error {
for _, handler := range h.handlers {
// Clone the record for each handler to avoid issues
if err := handler.Handle(ctx, r.Clone()); err != nil {
return err
}
}
return nil
}
func (h *multiHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
newHandlers := make([]slog.Handler, len(h.handlers))
for i, handler := range h.handlers {
newHandlers[i] = handler.WithAttrs(attrs)
}
return &multiHandler{handlers: newHandlers}
}
func (h *multiHandler) WithGroup(name string) slog.Handler {
newHandlers := make([]slog.Handler, len(h.handlers))
for i, handler := range h.handlers {
newHandlers[i] = handler.WithGroup(name)
}
return &multiHandler{handlers: newHandlers}
}
// extractSourceFilePath extracts the package/file:line from a PC
func extractSourceFilePath(pc uintptr) string {
if pc == 0 {
return ""
}
fs := runtime.CallersFrames([]uintptr{pc})
f, _ := fs.Next()
if f.File == "" {
return ""
}
// Extract just filename, not full path
idx := strings.LastIndexByte(f.File, '/')
if idx == -1 {
return fmt.Sprintf("%s:%d", f.File, f.Line)
}
// Get package/file:line
idx2 := strings.LastIndexByte(f.File[:idx], '/')
if idx2 == -1 {
return fmt.Sprintf("%s:%d", f.File[idx+1:], f.Line)
}
return fmt.Sprintf("%s:%d", f.File[idx2+1:], f.Line)
}