From 08563c32869c1e454afd0ba105132a216c3e051f Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Fri, 19 Apr 2024 00:02:00 +0200 Subject: [PATCH] uniform logging --- agent/agent.go | 42 +++++++-------- agent/agent_test.go | 19 +++---- agent/options.go | 10 ---- example/webui/actions.go | 9 ++-- example/webui/agentpool.go | 25 +++++---- example/webui/app.go | 19 +++---- example/webui/connector/discord.go | 18 +++---- example/webui/connector/githubissue.go | 23 ++++---- example/webui/connector/slack.go | 13 ++--- example/webui/connectors.go | 11 ++-- example/webui/main.go | 7 +-- example/webui/rag.go | 18 ++++--- xlog/xlog.go | 72 ++++++++++++++++++++++++++ 13 files changed, 178 insertions(+), 108 deletions(-) create mode 100644 xlog/xlog.go diff --git a/agent/agent.go b/agent/agent.go index 77a5033..51a666b 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -3,12 +3,13 @@ package agent import ( "context" "fmt" - "log/slog" "os" "strings" "sync" "time" + "github.com/mudler/local-agent-framework/xlog" + "github.com/mudler/local-agent-framework/action" "github.com/mudler/local-agent-framework/llm" "github.com/sashabaranov/go-openai" @@ -36,7 +37,6 @@ type Agent struct { selfEvaluationInProgress bool pause bool - logger *slog.Logger newConversations chan openai.ChatCompletionMessage } @@ -77,15 +77,15 @@ func New(opts ...Option) (*Agent, error) { } } - var programLevel = new(slog.LevelVar) // Info by default - h := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: programLevel}) - a.logger = slog.New(h) - programLevel.Set(a.options.logLevel) + // var programLevel = new(xlog.LevelVar) // Info by default + // h := xlog.NewTextHandler(os.Stdout, &xlog.HandlerOptions{Level: programLevel}) + // xlog = xlog.New(h) + //programLevel.Set(a.options.logLevel) - a.logger.Info("Agent in Debug mode", "agent", a.Character.Name) - a.logger.Info("Character", "agent", a.Character.Name, "character", a.Character.String()) - a.logger.Info("State", "agent", a.Character.Name, "state", a.State().String()) - a.logger.Info("Permanent goal", "agent", a.Character.Name, "goal", a.options.permanentGoal) + xlog.Info("Agent in Debug mode", "agent", a.Character.Name) + xlog.Info("Character", "agent", a.Character.Name, "character", a.Character.String()) + xlog.Info("State", "agent", a.Character.Name, "state", a.State().String()) + xlog.Info("Permanent goal", "agent", a.Character.Name, "goal", a.options.permanentGoal) return a, nil } @@ -123,7 +123,7 @@ func (a *Agent) Ask(opts ...JobOption) *JobResult { WithResultCallback(a.options.resultCallback), )..., ) - // slog.Info("Job created", text) + // xlog.Info("Job created", text) a.jobQueue <- j return j.Result.WaitResult() } @@ -181,7 +181,7 @@ func (a *Agent) runAction(chosenAction Action, decisionResult *decisionResult) ( } } - a.logger.Info("Running action", "action", chosenAction.Definition().Name, "agent", a.Character.Name) + xlog.Info("Running action", "action", chosenAction.Definition().Name, "agent", a.Character.Name) if chosenAction.Definition().Name.Is(action.StateActionName) { // We need to store the result in the state @@ -211,7 +211,7 @@ func (a *Agent) consumeJob(job *Job, role string) { a.Unlock() if paused { - a.logger.Info("Agent is paused, skipping job", "agent", a.Character.Name) + xlog.Info("Agent is paused, skipping job", "agent", a.Character.Name) job.Result.Finish(fmt.Errorf("agent is paused")) return } @@ -281,7 +281,7 @@ func (a *Agent) consumeJob(job *Job, role string) { if userMessage != "" { results, err := a.options.ragdb.Search(userMessage, a.options.kbResults) if err != nil { - a.logger.Info("Error finding similar strings inside KB:", "error", err) + xlog.Info("Error finding similar strings inside KB:", "error", err) // job.Result.Finish(fmt.Errorf("error finding similar strings inside KB: %w", err)) // return @@ -293,7 +293,7 @@ func (a *Agent) consumeJob(job *Job, role string) { for _, r := range results { formatResults += fmt.Sprintf("- %s \n", r) } - a.logger.Info("Found similar strings in KB", "agent", a.Character.Name, "results", formatResults) + xlog.Info("Found similar strings in KB", "agent", a.Character.Name, "results", formatResults) // a.currentConversation = append(a.currentConversation, // openai.ChatCompletionMessage{ @@ -363,12 +363,12 @@ func (a *Agent) consumeJob(job *Job, role string) { } if chosenAction.Definition().Name.Is(action.StopActionName) { - a.logger.Info("LLM decided to stop") + xlog.Info("LLM decided to stop") job.Result.Finish(nil) return } - a.logger.Info("Generating parameters", + xlog.Info("Generating parameters", "agent", a.Character.Name, "action", chosenAction.Definition().Name, "reasoning", reasoning, @@ -380,7 +380,7 @@ func (a *Agent) consumeJob(job *Job, role string) { return } - a.logger.Info( + xlog.Info( "Generated parameters", "agent", a.Character.Name, "action", chosenAction.Definition().Name, @@ -572,7 +572,7 @@ func (a *Agent) consumeJob(job *Job, role string) { // If we didn't got any message, we can use the response from the action if chosenAction.Definition().Name.Is(action.ReplyActionName) && msg.Content == "" || strings.Contains(msg.Content, "") { - a.logger.Info("No output returned from conversation, using the action response as a reply " + replyResponse.Message) + xlog.Info("No output returned from conversation, using the action response as a reply " + replyResponse.Message) msg = openai.ChatCompletionMessage{ Role: "assistant", @@ -594,7 +594,7 @@ func (a *Agent) periodicallyRun() { // This would be a special action that would be picked up by the agent // and would be used to contact the user. - a.logger.Info("START -- Periodically run is starting") + xlog.Info("START -- Periodically run is starting") if len(a.CurrentConversation()) != 0 { // Here the LLM could decide to store some part of the conversation too in the memory @@ -624,7 +624,7 @@ func (a *Agent) periodicallyRun() { a.consumeJob(whatNext, SystemRole) a.ResetConversation() - a.logger.Info("STOP -- Periodically run is done") + xlog.Info("STOP -- Periodically run is done") // Save results from state diff --git a/agent/agent_test.go b/agent/agent_test.go index a5a19bd..2f56186 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -3,7 +3,8 @@ package agent_test import ( "context" "fmt" - "log/slog" + + "github.com/mudler/local-agent-framework/xlog" "github.com/mudler/local-agent-framework/action" . "github.com/mudler/local-agent-framework/agent" @@ -20,13 +21,13 @@ var _ Action = &TestAction{} var debugOptions = []JobOption{ WithReasoningCallback(func(state ActionCurrentState) bool { - slog.Info("Reasoning", state) + xlog.Info("Reasoning", state) return true }), WithResultCallback(func(state ActionState) { - slog.Info("Reasoning", state.Reasoning) - slog.Info("Action", state.Action) - slog.Info("Result", state.Result) + xlog.Info("Reasoning", state.Reasoning) + xlog.Info("Action", state.Action) + xlog.Info("Result", state.Result) }), } @@ -197,13 +198,13 @@ var _ = Describe("Agent test", func() { EnableHUD, EnableStandaloneJob, WithAgentReasoningCallback(func(state ActionCurrentState) bool { - slog.Info("Reasoning", state) + xlog.Info("Reasoning", state) return true }), WithAgentResultCallback(func(state ActionState) { - slog.Info("Reasoning", state.Reasoning) - slog.Info("Action", state.Action) - slog.Info("Result", state.Result) + xlog.Info("Reasoning", state.Reasoning) + xlog.Info("Action", state.Action) + xlog.Info("Result", state.Result) }), WithActions( &FakeInternetAction{ diff --git a/agent/options.go b/agent/options.go index 6bf240e..22006a0 100644 --- a/agent/options.go +++ b/agent/options.go @@ -2,7 +2,6 @@ package agent import ( "context" - "log/slog" "strings" "time" ) @@ -22,7 +21,6 @@ type options struct { userActions Actions enableHUD, standaloneJob, showCharacter, enableKB bool - logLevel slog.Level canStopItself bool initiateConversations bool characterfile string @@ -55,7 +53,6 @@ func defaultOptions() *options { APIURL: "http://localhost:8080", Model: "echidna", }, - logLevel: slog.LevelInfo, character: Character{ Name: "John Doe", Age: "", @@ -92,13 +89,6 @@ var CanStopItself = func(o *options) error { return nil } -func LogLevel(level slog.Level) Option { - return func(o *options) error { - o.logLevel = level - return nil - } -} - func WithTimeout(timeout string) Option { return func(o *options) error { o.timeout = timeout diff --git a/example/webui/actions.go b/example/webui/actions.go index fc58fe9..f43a447 100644 --- a/example/webui/actions.go +++ b/example/webui/actions.go @@ -3,7 +3,8 @@ package main import ( "context" "encoding/json" - "log/slog" + + "github.com/mudler/local-agent-framework/xlog" . "github.com/mudler/local-agent-framework/agent" "github.com/mudler/local-agent-framework/external" @@ -36,14 +37,14 @@ func (a *AgentConfig) availableActions(ctx context.Context) []Action { actions := []Action{} for _, action := range a.Actions { - slog.Info("Set Action", action) + xlog.Info("Set Action", action) var config map[string]string if err := json.Unmarshal([]byte(action.Config), &config); err != nil { - slog.Info("Error unmarshalling action config", err) + xlog.Info("Error unmarshalling action config", err) continue } - slog.Info("Config", config) + xlog.Info("Config", config) switch action.Name { case ActionSearch: diff --git a/example/webui/agentpool.go b/example/webui/agentpool.go index 448531f..746a314 100644 --- a/example/webui/agentpool.go +++ b/example/webui/agentpool.go @@ -4,13 +4,14 @@ import ( "context" "encoding/json" "fmt" - "log/slog" "os" "path/filepath" "sort" "sync" "time" + "github.com/mudler/local-agent-framework/xlog" + . "github.com/mudler/local-agent-framework/agent" ) @@ -140,15 +141,15 @@ func (a *AgentPool) startAgentWithConfig(name string, config *AgentConfig) error connectors := config.availableConnectors() - slog.Info("Creating agent", name) - slog.Info("Model", model) - slog.Info("API URL", a.apiURL) + xlog.Info("Creating agent", name) + xlog.Info("Model", model) + xlog.Info("API URL", a.apiURL) actions := config.availableActions(ctx) stateFile, characterFile := a.stateFiles(name) - slog.Info("Actions", actions) + xlog.Info("Actions", actions) opts := []Option{ WithModel(model), WithLLMAPIURL(a.apiURL), @@ -163,7 +164,7 @@ func (a *AgentPool) startAgentWithConfig(name string, config *AgentConfig) error WithTimeout(timeout), WithRAGDB(a.ragDB), WithAgentReasoningCallback(func(state ActionCurrentState) bool { - slog.Info("Reasoning", state.Reasoning) + xlog.Info("Reasoning", state.Reasoning) manager.Send( NewMessage( fmt.Sprintf(`Thinking: %s`, htmlIfy(state.Reasoning)), @@ -186,7 +187,7 @@ func (a *AgentPool) startAgentWithConfig(name string, config *AgentConfig) error a.agentStatus[name].addResult(state) a.Unlock() - slog.Info("Reasoning", state.Reasoning) + xlog.Info("Reasoning", state.Reasoning) text := fmt.Sprintf(`Reasoning: %s Action taken: %+v @@ -212,9 +213,7 @@ func (a *AgentPool) startAgentWithConfig(name string, config *AgentConfig) error if config.HUD { opts = append(opts, EnableHUD) } - if os.Getenv("DEBUG") != "" { - opts = append(opts, LogLevel(slog.LevelDebug)) - } + if config.StandaloneJob { opts = append(opts, EnableStandaloneJob) } @@ -240,7 +239,7 @@ func (a *AgentPool) startAgentWithConfig(name string, config *AgentConfig) error opts = append(opts, EnableKnowledgeBaseWithResults(config.KnowledgeBaseResults)) } - slog.Info("Starting agent", "name", name, "config", config) + xlog.Info("Starting agent", "name", name, "config", config) agent, err := New(opts...) if err != nil { return err @@ -251,7 +250,7 @@ func (a *AgentPool) startAgentWithConfig(name string, config *AgentConfig) error go func() { if err := agent.Run(); err != nil { - slog.Info("Agent stop: ", err.Error()) + xlog.Info("Agent stop: ", err.Error()) } }() @@ -302,7 +301,7 @@ func (a *AgentPool) Start(name string) error { if err != nil { return fmt.Errorf("agent %s failed to start: %w", name, err) } - slog.Info("Agent started", "name", name) + xlog.Info("Agent started", "name", name) return nil } if config, ok := a.pool[name]; ok { diff --git a/example/webui/app.go b/example/webui/app.go index d2d9e72..e78a4b1 100644 --- a/example/webui/app.go +++ b/example/webui/app.go @@ -4,10 +4,11 @@ import ( "bytes" "encoding/json" "fmt" - "log/slog" "net/http" "os" + "github.com/mudler/local-agent-framework/xlog" + . "github.com/mudler/local-agent-framework/agent" "github.com/donseba/go-htmx" @@ -54,7 +55,7 @@ func (a *App) KnowledgeBaseFile(db *InMemoryDatabase) func(c *fiber.Ctx) error { return err } - slog.Info("File uploaded to: " + destination) + xlog.Info("File uploaded to: " + destination) fmt.Printf("Payload: %+v\n", payload) content, err := readPdf(destination) // Read local pdf file @@ -62,7 +63,7 @@ func (a *App) KnowledgeBaseFile(db *InMemoryDatabase) func(c *fiber.Ctx) error { panic(err) } - slog.Info("Content is", content) + xlog.Info("Content is", content) chunkSize := defaultChunkSize if payload.ChunkSize > 0 { chunkSize = payload.ChunkSize @@ -131,7 +132,7 @@ func (a *App) Notify(pool *AgentPool) func(c *fiber.Ctx) error { func (a *App) Delete(pool *AgentPool) func(c *fiber.Ctx) error { return func(c *fiber.Ctx) error { if err := pool.Remove(c.Params("name")); err != nil { - slog.Info("Error removing agent", err) + xlog.Info("Error removing agent", err) return c.Status(http.StatusInternalServerError).SendString(err.Error()) } return c.Redirect("/agents") @@ -140,7 +141,7 @@ func (a *App) Delete(pool *AgentPool) func(c *fiber.Ctx) error { func (a *App) Pause(pool *AgentPool) func(c *fiber.Ctx) error { return func(c *fiber.Ctx) error { - slog.Info("Pausing agent", c.Params("name")) + xlog.Info("Pausing agent", c.Params("name")) agent := pool.GetAgent(c.Params("name")) if agent != nil { agent.Pause() @@ -218,7 +219,7 @@ func (a *App) ImportAgent(pool *AgentPool) func(c *fiber.Ctx) error { return err } - slog.Info("Importing agent", config.Name) + xlog.Info("Importing agent", config.Name) if config.Name == "" { c.Status(http.StatusBadRequest).SendString("Name is required") @@ -258,16 +259,16 @@ func (a *App) Chat(pool *AgentPool) func(c *fiber.Ctx) error { go func() { agent := pool.GetAgent(agentName) if agent == nil { - slog.Info("Agent not found in pool", c.Params("name")) + xlog.Info("Agent not found in pool", c.Params("name")) return } res := agent.Ask( WithText(query), ) if res.Error != nil { - slog.Error("Error asking agent", "agent", agentName, "error", res.Error) + xlog.Error("Error asking agent", "agent", agentName, "error", res.Error) } else { - slog.Info("we got a response from the agent", "agent", agentName, "response", res.Response) + xlog.Info("we got a response from the agent", "agent", agentName, "response", res.Response) } manager.Send( NewMessage( diff --git a/example/webui/connector/discord.go b/example/webui/connector/discord.go index 3ffcc52..ffd1bd8 100644 --- a/example/webui/connector/discord.go +++ b/example/webui/connector/discord.go @@ -1,11 +1,11 @@ package connector import ( - "log/slog" "strings" "github.com/bwmarrin/discordgo" "github.com/mudler/local-agent-framework/agent" + "github.com/mudler/local-agent-framework/xlog" ) type Discord struct { @@ -39,7 +39,7 @@ func (d *Discord) Start(a *agent.Agent) { // Create a new Discord session using the provided bot token. dg, err := discordgo.New(Token) if err != nil { - slog.Info("error creating Discord session,", err) + xlog.Info("error creating Discord session,", err) return } @@ -52,15 +52,15 @@ func (d *Discord) Start(a *agent.Agent) { // Open a websocket connection to Discord and begin listening. err = dg.Open() if err != nil { - slog.Info("error opening connection,", err) + xlog.Info("error opening connection,", err) return } go func() { - slog.Info("Discord bot is now running. Press CTRL-C to exit.") + xlog.Info("Discord bot is now running. Press CTRL-C to exit.") <-a.Context().Done() dg.Close() - slog.Info("Discord bot is now stopped.") + xlog.Info("Discord bot is now stopped.") }() } @@ -78,21 +78,21 @@ func (d *Discord) messageCreate(a *agent.Agent) func(s *discordgo.Session, m *di content := m.Content content = strings.ReplaceAll(content, "<@"+s.State.User.ID+"> ", "") - slog.Info("Received message", "content", content) + xlog.Info("Received message", "content", content) job := a.Ask( agent.WithText( content, ), ) if job.Error != nil { - slog.Info("error asking agent,", job.Error) + xlog.Info("error asking agent,", job.Error) return } - slog.Info("Response", "response", job.Response) + xlog.Info("Response", "response", job.Response) _, err := s.ChannelMessageSend(m.ChannelID, job.Response) if err != nil { - slog.Info("error sending message,", err) + xlog.Info("error sending message,", err) } } diff --git a/example/webui/connector/githubissue.go b/example/webui/connector/githubissue.go index e91a786..46325ca 100644 --- a/example/webui/connector/githubissue.go +++ b/example/webui/connector/githubissue.go @@ -2,12 +2,13 @@ package connector import ( "fmt" - "log/slog" "strings" "time" "github.com/google/go-github/v61/github" "github.com/mudler/local-agent-framework/agent" + "github.com/mudler/local-agent-framework/xlog" + "github.com/sashabaranov/go-openai" ) @@ -58,10 +59,10 @@ func (g *GithubIssues) Start(a *agent.Agent) { for { select { case <-ticker.C: - slog.Info("Looking into github issues...") + xlog.Info("Looking into github issues...") g.issuesService() case <-a.Context().Done(): - slog.Info("GithubIssues connector is now stopping") + xlog.Info("GithubIssues connector is now stopping") return } } @@ -81,7 +82,7 @@ func (g *GithubIssues) issuesService() { g.repository, &github.IssueListByRepoOptions{}) if err != nil { - slog.Info("Error listing issues", err) + xlog.Info("Error listing issues", err) } for _, issue := range issues { // Do something with the issue @@ -101,7 +102,7 @@ func (g *GithubIssues) issuesService() { } if userName == user.GetLogin() { - slog.Info("Ignoring issue opened by the bot") + xlog.Info("Ignoring issue opened by the bot") continue } messages := []openai.ChatCompletionMessage{ @@ -135,7 +136,7 @@ func (g *GithubIssues) issuesService() { // if last comment is from the user and mentions the bot username, we must answer if comment.User.GetName() != user.GetLogin() && len(comments)-1 == i { if strings.Contains(comment.GetBody(), fmt.Sprintf("@%s", user.GetLogin())) { - slog.Info("Bot was mentioned in the last comment") + xlog.Info("Bot was mentioned in the last comment") mustAnswer = true } } @@ -143,9 +144,9 @@ func (g *GithubIssues) issuesService() { if len(comments) == 0 || !botAnsweredAlready { // if no comments, or bot didn't answer yet, we must answer - slog.Info("No comments, or bot didn't answer yet") - slog.Info("Comments:", len(comments)) - slog.Info("Bot answered already", botAnsweredAlready) + xlog.Info("No comments, or bot didn't answer yet") + xlog.Info("Comments:", len(comments)) + xlog.Info("Bot answered already", botAnsweredAlready) mustAnswer = true } @@ -157,7 +158,7 @@ func (g *GithubIssues) issuesService() { agent.WithConversationHistory(messages), ) if res.Error != nil { - slog.Error("Error asking", "error", res.Error) + xlog.Error("Error asking", "error", res.Error) return } @@ -169,7 +170,7 @@ func (g *GithubIssues) issuesService() { }, ) if err != nil { - slog.Error("Error creating comment", "error", err) + xlog.Error("Error creating comment", "error", err) } } } diff --git a/example/webui/connector/slack.go b/example/webui/connector/slack.go index ef1a5e7..5a9e2a6 100644 --- a/example/webui/connector/slack.go +++ b/example/webui/connector/slack.go @@ -3,10 +3,11 @@ package connector import ( "fmt" "log" - "log/slog" "os" "strings" + "github.com/mudler/local-agent-framework/xlog" + "github.com/mudler/local-agent-framework/agent" "github.com/slack-go/slack/socketmode" @@ -61,11 +62,11 @@ func (t *Slack) Start(a *agent.Agent) { for evt := range client.Events { switch evt.Type { case socketmode.EventTypeConnecting: - slog.Info("Connecting to Slack with Socket Mode...") + xlog.Info("Connecting to Slack with Socket Mode...") case socketmode.EventTypeConnectionError: - slog.Info("Connection failed. Retrying later...") + xlog.Info("Connection failed. Retrying later...") case socketmode.EventTypeConnected: - slog.Info("Connected to Slack with Socket Mode.") + xlog.Info("Connected to Slack with Socket Mode.") case socketmode.EventTypeEventsAPI: eventsAPIEvent, ok := evt.Data.(slackevents.EventsAPIEvent) if !ok { @@ -92,7 +93,7 @@ func (t *Slack) Start(a *agent.Agent) { if t.channelID == "" && !t.alwaysReply || // If we have set alwaysReply and no channelID t.channelID != ev.Channel { // If we have a channelID and it's not the same as the event channel // Skip messages from other channels - slog.Info("Skipping reply to channel", ev.Channel, t.channelID) + xlog.Info("Skipping reply to channel", ev.Channel, t.channelID) continue } @@ -124,7 +125,7 @@ func (t *Slack) Start(a *agent.Agent) { // strip our id from the message message = strings.ReplaceAll(message, "<@"+b.UserID+"> ", "") - slog.Info("Message", message) + xlog.Info("Message", message) go func() { res := a.Ask( diff --git a/example/webui/connectors.go b/example/webui/connectors.go index 7667d33..47faea5 100644 --- a/example/webui/connectors.go +++ b/example/webui/connectors.go @@ -2,7 +2,8 @@ package main import ( "encoding/json" - "log/slog" + + "github.com/mudler/local-agent-framework/xlog" . "github.com/mudler/local-agent-framework/agent" @@ -34,20 +35,20 @@ func (a *AgentConfig) availableConnectors() []Connector { connectors := []Connector{} for _, c := range a.Connector { - slog.Info("Set Connector", c) + xlog.Info("Set Connector", c) var config map[string]string if err := json.Unmarshal([]byte(c.Config), &config); err != nil { - slog.Info("Error unmarshalling connector config", err) + xlog.Info("Error unmarshalling connector config", err) continue } - slog.Info("Config", config) + xlog.Info("Config", config) switch c.Type { case ConnectorTelegram: cc, err := connector.NewTelegramConnector(config) if err != nil { - slog.Info("Error creating telegram connector", err) + xlog.Info("Error creating telegram connector", err) continue } diff --git a/example/webui/main.go b/example/webui/main.go index 795efd0..e1df6f2 100644 --- a/example/webui/main.go +++ b/example/webui/main.go @@ -3,10 +3,11 @@ package main import ( "embed" "log" - "log/slog" "net/http" "os" + "github.com/mudler/local-agent-framework/xlog" + "github.com/donseba/go-htmx" fiber "github.com/gofiber/fiber/v2" "github.com/gofiber/template/html/v2" @@ -79,9 +80,9 @@ func main() { } if len(db.Database) > 0 && kbdisableIndexing != "true" { - slog.Info("Loading knowledgebase from disk, to skip run with KBDISABLEINDEX=true") + xlog.Info("Loading knowledgebase from disk, to skip run with KBDISABLEINDEX=true") if err := db.SaveToStore(); err != nil { - slog.Info("Error storing in the KB", err) + xlog.Info("Error storing in the KB", err) } } diff --git a/example/webui/rag.go b/example/webui/rag.go index 7d5ba35..54c3283 100644 --- a/example/webui/rag.go +++ b/example/webui/rag.go @@ -4,7 +4,9 @@ import ( "encoding/json" "fmt" "io" - "log/slog" + + "github.com/mudler/local-agent-framework/xlog" + "net/http" "os" "path/filepath" @@ -121,7 +123,7 @@ func getWebPage(url string) (string, error) { func Sitemap(url string) (res []string, err error) { err = sitemap.ParseFromSite(url, func(e sitemap.Entry) error { - slog.Info("Sitemap page: " + e.GetLocation()) + xlog.Info("Sitemap page: " + e.GetLocation()) content, err := getWebPage(e.GetLocation()) if err == nil { res = append(res, content) @@ -134,10 +136,10 @@ func Sitemap(url string) (res []string, err error) { func WebsiteToKB(website string, chunkSize int, db *InMemoryDatabase) { content, err := Sitemap(website) if err != nil { - slog.Info("Error walking sitemap for website", err) + xlog.Info("Error walking sitemap for website", err) } - slog.Info("Found pages: ", len(content)) - slog.Info("ChunkSize: ", chunkSize) + xlog.Info("Found pages: ", len(content)) + xlog.Info("ChunkSize: ", chunkSize) StringsToKB(db, chunkSize, content...) } @@ -145,9 +147,9 @@ func WebsiteToKB(website string, chunkSize int, db *InMemoryDatabase) { func StringsToKB(db *InMemoryDatabase, chunkSize int, content ...string) { for _, c := range content { chunks := splitParagraphIntoChunks(c, chunkSize) - slog.Info("chunks: ", len(chunks)) + xlog.Info("chunks: ", len(chunks)) for _, chunk := range chunks { - slog.Info("Chunk size: ", len(chunk)) + xlog.Info("Chunk size: ", len(chunk)) db.AddEntry(chunk) } @@ -155,7 +157,7 @@ func StringsToKB(db *InMemoryDatabase, chunkSize int, content ...string) { } if err := db.SaveToStore(); err != nil { - slog.Info("Error storing in the KB", err) + xlog.Info("Error storing in the KB", err) } } diff --git a/xlog/xlog.go b/xlog/xlog.go new file mode 100644 index 0000000..e896c80 --- /dev/null +++ b/xlog/xlog.go @@ -0,0 +1,72 @@ +package xlog + +import ( + "context" + "log/slog" + "os" + "runtime" +) + +var logger *slog.Logger + +func init() { + var level = slog.LevelDebug + + switch os.Getenv("LOG_LEVEL") { + case "info": + level = slog.LevelInfo + case "warn": + level = slog.LevelWarn + case "error": + level = slog.LevelError + case "debug": + level = slog.LevelDebug + } + + var opts = &slog.HandlerOptions{ + Level: level, + } + + var handler slog.Handler + + if os.Getenv("LOG_FORMAT") == "json" { + handler = slog.NewJSONHandler(os.Stdout, opts) + } else { + handler = slog.NewTextHandler(os.Stdout, opts) + } + logger = slog.New(handler) +} + +func _log(level slog.Level, msg string, args ...any) { + _, f, l, _ := runtime.Caller(2) + group := slog.Group( + "source", + slog.Attr{ + Key: "file", + Value: slog.AnyValue(f), + }, + slog.Attr{ + Key: "L", + Value: slog.AnyValue(l), + }, + ) + args = append(args, group) + logger.Log(context.Background(), level, msg, args...) +} + +func Info(msg string, args ...any) { + _log(slog.LevelInfo, msg, args...) +} + +func Debug(msg string, args ...any) { + _log(slog.LevelDebug, msg, args...) + logger.Debug(msg, args...) +} + +func Error(msg string, args ...any) { + _log(slog.LevelError, msg, args...) +} + +func Warn(msg string, args ...any) { + _log(slog.LevelWarn, msg, args...) +}