uniform logging
This commit is contained in:
@@ -3,12 +3,13 @@ package agent
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/mudler/local-agent-framework/xlog"
|
||||||
|
|
||||||
"github.com/mudler/local-agent-framework/action"
|
"github.com/mudler/local-agent-framework/action"
|
||||||
"github.com/mudler/local-agent-framework/llm"
|
"github.com/mudler/local-agent-framework/llm"
|
||||||
"github.com/sashabaranov/go-openai"
|
"github.com/sashabaranov/go-openai"
|
||||||
@@ -36,7 +37,6 @@ type Agent struct {
|
|||||||
selfEvaluationInProgress bool
|
selfEvaluationInProgress bool
|
||||||
pause bool
|
pause bool
|
||||||
|
|
||||||
logger *slog.Logger
|
|
||||||
newConversations chan openai.ChatCompletionMessage
|
newConversations chan openai.ChatCompletionMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,15 +77,15 @@ func New(opts ...Option) (*Agent, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var programLevel = new(slog.LevelVar) // Info by default
|
// var programLevel = new(xlog.LevelVar) // Info by default
|
||||||
h := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: programLevel})
|
// h := xlog.NewTextHandler(os.Stdout, &xlog.HandlerOptions{Level: programLevel})
|
||||||
a.logger = slog.New(h)
|
// xlog = xlog.New(h)
|
||||||
programLevel.Set(a.options.logLevel)
|
//programLevel.Set(a.options.logLevel)
|
||||||
|
|
||||||
a.logger.Info("Agent in Debug mode", "agent", a.Character.Name)
|
xlog.Info("Agent in Debug mode", "agent", a.Character.Name)
|
||||||
a.logger.Info("Character", "agent", a.Character.Name, "character", a.Character.String())
|
xlog.Info("Character", "agent", a.Character.Name, "character", a.Character.String())
|
||||||
a.logger.Info("State", "agent", a.Character.Name, "state", a.State().String())
|
xlog.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("Permanent goal", "agent", a.Character.Name, "goal", a.options.permanentGoal)
|
||||||
|
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,7 @@ func (a *Agent) Ask(opts ...JobOption) *JobResult {
|
|||||||
WithResultCallback(a.options.resultCallback),
|
WithResultCallback(a.options.resultCallback),
|
||||||
)...,
|
)...,
|
||||||
)
|
)
|
||||||
// slog.Info("Job created", text)
|
// xlog.Info("Job created", text)
|
||||||
a.jobQueue <- j
|
a.jobQueue <- j
|
||||||
return j.Result.WaitResult()
|
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) {
|
if chosenAction.Definition().Name.Is(action.StateActionName) {
|
||||||
// We need to store the result in the state
|
// We need to store the result in the state
|
||||||
@@ -211,7 +211,7 @@ func (a *Agent) consumeJob(job *Job, role string) {
|
|||||||
a.Unlock()
|
a.Unlock()
|
||||||
|
|
||||||
if paused {
|
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"))
|
job.Result.Finish(fmt.Errorf("agent is paused"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -281,7 +281,7 @@ func (a *Agent) consumeJob(job *Job, role string) {
|
|||||||
if userMessage != "" {
|
if userMessage != "" {
|
||||||
results, err := a.options.ragdb.Search(userMessage, a.options.kbResults)
|
results, err := a.options.ragdb.Search(userMessage, a.options.kbResults)
|
||||||
if err != nil {
|
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))
|
// job.Result.Finish(fmt.Errorf("error finding similar strings inside KB: %w", err))
|
||||||
// return
|
// return
|
||||||
@@ -293,7 +293,7 @@ func (a *Agent) consumeJob(job *Job, role string) {
|
|||||||
for _, r := range results {
|
for _, r := range results {
|
||||||
formatResults += fmt.Sprintf("- %s \n", r)
|
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,
|
// a.currentConversation = append(a.currentConversation,
|
||||||
// openai.ChatCompletionMessage{
|
// openai.ChatCompletionMessage{
|
||||||
@@ -363,12 +363,12 @@ func (a *Agent) consumeJob(job *Job, role string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if chosenAction.Definition().Name.Is(action.StopActionName) {
|
if chosenAction.Definition().Name.Is(action.StopActionName) {
|
||||||
a.logger.Info("LLM decided to stop")
|
xlog.Info("LLM decided to stop")
|
||||||
job.Result.Finish(nil)
|
job.Result.Finish(nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
a.logger.Info("Generating parameters",
|
xlog.Info("Generating parameters",
|
||||||
"agent", a.Character.Name,
|
"agent", a.Character.Name,
|
||||||
"action", chosenAction.Definition().Name,
|
"action", chosenAction.Definition().Name,
|
||||||
"reasoning", reasoning,
|
"reasoning", reasoning,
|
||||||
@@ -380,7 +380,7 @@ func (a *Agent) consumeJob(job *Job, role string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
a.logger.Info(
|
xlog.Info(
|
||||||
"Generated parameters",
|
"Generated parameters",
|
||||||
"agent", a.Character.Name,
|
"agent", a.Character.Name,
|
||||||
"action", chosenAction.Definition().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 we didn't got any message, we can use the response from the action
|
||||||
if chosenAction.Definition().Name.Is(action.ReplyActionName) && msg.Content == "" ||
|
if chosenAction.Definition().Name.Is(action.ReplyActionName) && msg.Content == "" ||
|
||||||
strings.Contains(msg.Content, "<tool_call>") {
|
strings.Contains(msg.Content, "<tool_call>") {
|
||||||
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{
|
msg = openai.ChatCompletionMessage{
|
||||||
Role: "assistant",
|
Role: "assistant",
|
||||||
@@ -594,7 +594,7 @@ func (a *Agent) periodicallyRun() {
|
|||||||
// This would be a special action that would be picked up by the agent
|
// This would be a special action that would be picked up by the agent
|
||||||
// and would be used to contact the user.
|
// 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 {
|
if len(a.CurrentConversation()) != 0 {
|
||||||
// Here the LLM could decide to store some part of the conversation too in the memory
|
// 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.consumeJob(whatNext, SystemRole)
|
||||||
a.ResetConversation()
|
a.ResetConversation()
|
||||||
|
|
||||||
a.logger.Info("STOP -- Periodically run is done")
|
xlog.Info("STOP -- Periodically run is done")
|
||||||
|
|
||||||
// Save results from state
|
// Save results from state
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ package agent_test
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
|
||||||
|
"github.com/mudler/local-agent-framework/xlog"
|
||||||
|
|
||||||
"github.com/mudler/local-agent-framework/action"
|
"github.com/mudler/local-agent-framework/action"
|
||||||
. "github.com/mudler/local-agent-framework/agent"
|
. "github.com/mudler/local-agent-framework/agent"
|
||||||
@@ -20,13 +21,13 @@ var _ Action = &TestAction{}
|
|||||||
|
|
||||||
var debugOptions = []JobOption{
|
var debugOptions = []JobOption{
|
||||||
WithReasoningCallback(func(state ActionCurrentState) bool {
|
WithReasoningCallback(func(state ActionCurrentState) bool {
|
||||||
slog.Info("Reasoning", state)
|
xlog.Info("Reasoning", state)
|
||||||
return true
|
return true
|
||||||
}),
|
}),
|
||||||
WithResultCallback(func(state ActionState) {
|
WithResultCallback(func(state ActionState) {
|
||||||
slog.Info("Reasoning", state.Reasoning)
|
xlog.Info("Reasoning", state.Reasoning)
|
||||||
slog.Info("Action", state.Action)
|
xlog.Info("Action", state.Action)
|
||||||
slog.Info("Result", state.Result)
|
xlog.Info("Result", state.Result)
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,13 +198,13 @@ var _ = Describe("Agent test", func() {
|
|||||||
EnableHUD,
|
EnableHUD,
|
||||||
EnableStandaloneJob,
|
EnableStandaloneJob,
|
||||||
WithAgentReasoningCallback(func(state ActionCurrentState) bool {
|
WithAgentReasoningCallback(func(state ActionCurrentState) bool {
|
||||||
slog.Info("Reasoning", state)
|
xlog.Info("Reasoning", state)
|
||||||
return true
|
return true
|
||||||
}),
|
}),
|
||||||
WithAgentResultCallback(func(state ActionState) {
|
WithAgentResultCallback(func(state ActionState) {
|
||||||
slog.Info("Reasoning", state.Reasoning)
|
xlog.Info("Reasoning", state.Reasoning)
|
||||||
slog.Info("Action", state.Action)
|
xlog.Info("Action", state.Action)
|
||||||
slog.Info("Result", state.Result)
|
xlog.Info("Result", state.Result)
|
||||||
}),
|
}),
|
||||||
WithActions(
|
WithActions(
|
||||||
&FakeInternetAction{
|
&FakeInternetAction{
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package agent
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"log/slog"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -22,7 +21,6 @@ type options struct {
|
|||||||
userActions Actions
|
userActions Actions
|
||||||
enableHUD, standaloneJob, showCharacter, enableKB bool
|
enableHUD, standaloneJob, showCharacter, enableKB bool
|
||||||
|
|
||||||
logLevel slog.Level
|
|
||||||
canStopItself bool
|
canStopItself bool
|
||||||
initiateConversations bool
|
initiateConversations bool
|
||||||
characterfile string
|
characterfile string
|
||||||
@@ -55,7 +53,6 @@ func defaultOptions() *options {
|
|||||||
APIURL: "http://localhost:8080",
|
APIURL: "http://localhost:8080",
|
||||||
Model: "echidna",
|
Model: "echidna",
|
||||||
},
|
},
|
||||||
logLevel: slog.LevelInfo,
|
|
||||||
character: Character{
|
character: Character{
|
||||||
Name: "John Doe",
|
Name: "John Doe",
|
||||||
Age: "",
|
Age: "",
|
||||||
@@ -92,13 +89,6 @@ var CanStopItself = func(o *options) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func LogLevel(level slog.Level) Option {
|
|
||||||
return func(o *options) error {
|
|
||||||
o.logLevel = level
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithTimeout(timeout string) Option {
|
func WithTimeout(timeout string) Option {
|
||||||
return func(o *options) error {
|
return func(o *options) error {
|
||||||
o.timeout = timeout
|
o.timeout = timeout
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log/slog"
|
|
||||||
|
"github.com/mudler/local-agent-framework/xlog"
|
||||||
|
|
||||||
. "github.com/mudler/local-agent-framework/agent"
|
. "github.com/mudler/local-agent-framework/agent"
|
||||||
"github.com/mudler/local-agent-framework/external"
|
"github.com/mudler/local-agent-framework/external"
|
||||||
@@ -36,14 +37,14 @@ func (a *AgentConfig) availableActions(ctx context.Context) []Action {
|
|||||||
actions := []Action{}
|
actions := []Action{}
|
||||||
|
|
||||||
for _, action := range a.Actions {
|
for _, action := range a.Actions {
|
||||||
slog.Info("Set Action", action)
|
xlog.Info("Set Action", action)
|
||||||
|
|
||||||
var config map[string]string
|
var config map[string]string
|
||||||
if err := json.Unmarshal([]byte(action.Config), &config); err != nil {
|
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
|
continue
|
||||||
}
|
}
|
||||||
slog.Info("Config", config)
|
xlog.Info("Config", config)
|
||||||
|
|
||||||
switch action.Name {
|
switch action.Name {
|
||||||
case ActionSearch:
|
case ActionSearch:
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/mudler/local-agent-framework/xlog"
|
||||||
|
|
||||||
. "github.com/mudler/local-agent-framework/agent"
|
. "github.com/mudler/local-agent-framework/agent"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -140,15 +141,15 @@ func (a *AgentPool) startAgentWithConfig(name string, config *AgentConfig) error
|
|||||||
|
|
||||||
connectors := config.availableConnectors()
|
connectors := config.availableConnectors()
|
||||||
|
|
||||||
slog.Info("Creating agent", name)
|
xlog.Info("Creating agent", name)
|
||||||
slog.Info("Model", model)
|
xlog.Info("Model", model)
|
||||||
slog.Info("API URL", a.apiURL)
|
xlog.Info("API URL", a.apiURL)
|
||||||
|
|
||||||
actions := config.availableActions(ctx)
|
actions := config.availableActions(ctx)
|
||||||
|
|
||||||
stateFile, characterFile := a.stateFiles(name)
|
stateFile, characterFile := a.stateFiles(name)
|
||||||
|
|
||||||
slog.Info("Actions", actions)
|
xlog.Info("Actions", actions)
|
||||||
opts := []Option{
|
opts := []Option{
|
||||||
WithModel(model),
|
WithModel(model),
|
||||||
WithLLMAPIURL(a.apiURL),
|
WithLLMAPIURL(a.apiURL),
|
||||||
@@ -163,7 +164,7 @@ func (a *AgentPool) startAgentWithConfig(name string, config *AgentConfig) error
|
|||||||
WithTimeout(timeout),
|
WithTimeout(timeout),
|
||||||
WithRAGDB(a.ragDB),
|
WithRAGDB(a.ragDB),
|
||||||
WithAgentReasoningCallback(func(state ActionCurrentState) bool {
|
WithAgentReasoningCallback(func(state ActionCurrentState) bool {
|
||||||
slog.Info("Reasoning", state.Reasoning)
|
xlog.Info("Reasoning", state.Reasoning)
|
||||||
manager.Send(
|
manager.Send(
|
||||||
NewMessage(
|
NewMessage(
|
||||||
fmt.Sprintf(`Thinking: %s`, htmlIfy(state.Reasoning)),
|
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.agentStatus[name].addResult(state)
|
||||||
a.Unlock()
|
a.Unlock()
|
||||||
slog.Info("Reasoning", state.Reasoning)
|
xlog.Info("Reasoning", state.Reasoning)
|
||||||
|
|
||||||
text := fmt.Sprintf(`Reasoning: %s
|
text := fmt.Sprintf(`Reasoning: %s
|
||||||
Action taken: %+v
|
Action taken: %+v
|
||||||
@@ -212,9 +213,7 @@ func (a *AgentPool) startAgentWithConfig(name string, config *AgentConfig) error
|
|||||||
if config.HUD {
|
if config.HUD {
|
||||||
opts = append(opts, EnableHUD)
|
opts = append(opts, EnableHUD)
|
||||||
}
|
}
|
||||||
if os.Getenv("DEBUG") != "" {
|
|
||||||
opts = append(opts, LogLevel(slog.LevelDebug))
|
|
||||||
}
|
|
||||||
if config.StandaloneJob {
|
if config.StandaloneJob {
|
||||||
opts = append(opts, EnableStandaloneJob)
|
opts = append(opts, EnableStandaloneJob)
|
||||||
}
|
}
|
||||||
@@ -240,7 +239,7 @@ func (a *AgentPool) startAgentWithConfig(name string, config *AgentConfig) error
|
|||||||
opts = append(opts, EnableKnowledgeBaseWithResults(config.KnowledgeBaseResults))
|
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...)
|
agent, err := New(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -251,7 +250,7 @@ func (a *AgentPool) startAgentWithConfig(name string, config *AgentConfig) error
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if err := agent.Run(); err != nil {
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("agent %s failed to start: %w", name, err)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
if config, ok := a.pool[name]; ok {
|
if config, ok := a.pool[name]; ok {
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/mudler/local-agent-framework/xlog"
|
||||||
|
|
||||||
. "github.com/mudler/local-agent-framework/agent"
|
. "github.com/mudler/local-agent-framework/agent"
|
||||||
|
|
||||||
"github.com/donseba/go-htmx"
|
"github.com/donseba/go-htmx"
|
||||||
@@ -54,7 +55,7 @@ func (a *App) KnowledgeBaseFile(db *InMemoryDatabase) func(c *fiber.Ctx) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Info("File uploaded to: " + destination)
|
xlog.Info("File uploaded to: " + destination)
|
||||||
fmt.Printf("Payload: %+v\n", payload)
|
fmt.Printf("Payload: %+v\n", payload)
|
||||||
|
|
||||||
content, err := readPdf(destination) // Read local pdf file
|
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)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Info("Content is", content)
|
xlog.Info("Content is", content)
|
||||||
chunkSize := defaultChunkSize
|
chunkSize := defaultChunkSize
|
||||||
if payload.ChunkSize > 0 {
|
if payload.ChunkSize > 0 {
|
||||||
chunkSize = payload.ChunkSize
|
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 {
|
func (a *App) Delete(pool *AgentPool) func(c *fiber.Ctx) error {
|
||||||
return func(c *fiber.Ctx) error {
|
return func(c *fiber.Ctx) error {
|
||||||
if err := pool.Remove(c.Params("name")); err != nil {
|
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.Status(http.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
return c.Redirect("/agents")
|
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 {
|
func (a *App) Pause(pool *AgentPool) func(c *fiber.Ctx) error {
|
||||||
return 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"))
|
agent := pool.GetAgent(c.Params("name"))
|
||||||
if agent != nil {
|
if agent != nil {
|
||||||
agent.Pause()
|
agent.Pause()
|
||||||
@@ -218,7 +219,7 @@ func (a *App) ImportAgent(pool *AgentPool) func(c *fiber.Ctx) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Info("Importing agent", config.Name)
|
xlog.Info("Importing agent", config.Name)
|
||||||
|
|
||||||
if config.Name == "" {
|
if config.Name == "" {
|
||||||
c.Status(http.StatusBadRequest).SendString("Name is required")
|
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() {
|
go func() {
|
||||||
agent := pool.GetAgent(agentName)
|
agent := pool.GetAgent(agentName)
|
||||||
if agent == nil {
|
if agent == nil {
|
||||||
slog.Info("Agent not found in pool", c.Params("name"))
|
xlog.Info("Agent not found in pool", c.Params("name"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res := agent.Ask(
|
res := agent.Ask(
|
||||||
WithText(query),
|
WithText(query),
|
||||||
)
|
)
|
||||||
if res.Error != nil {
|
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 {
|
} 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(
|
manager.Send(
|
||||||
NewMessage(
|
NewMessage(
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package connector
|
package connector
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log/slog"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
"github.com/mudler/local-agent-framework/agent"
|
"github.com/mudler/local-agent-framework/agent"
|
||||||
|
"github.com/mudler/local-agent-framework/xlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Discord struct {
|
type Discord struct {
|
||||||
@@ -39,7 +39,7 @@ func (d *Discord) Start(a *agent.Agent) {
|
|||||||
// Create a new Discord session using the provided bot token.
|
// Create a new Discord session using the provided bot token.
|
||||||
dg, err := discordgo.New(Token)
|
dg, err := discordgo.New(Token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Info("error creating Discord session,", err)
|
xlog.Info("error creating Discord session,", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,15 +52,15 @@ func (d *Discord) Start(a *agent.Agent) {
|
|||||||
// Open a websocket connection to Discord and begin listening.
|
// Open a websocket connection to Discord and begin listening.
|
||||||
err = dg.Open()
|
err = dg.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Info("error opening connection,", err)
|
xlog.Info("error opening connection,", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
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()
|
<-a.Context().Done()
|
||||||
dg.Close()
|
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 := m.Content
|
||||||
|
|
||||||
content = strings.ReplaceAll(content, "<@"+s.State.User.ID+"> ", "")
|
content = strings.ReplaceAll(content, "<@"+s.State.User.ID+"> ", "")
|
||||||
slog.Info("Received message", "content", content)
|
xlog.Info("Received message", "content", content)
|
||||||
job := a.Ask(
|
job := a.Ask(
|
||||||
agent.WithText(
|
agent.WithText(
|
||||||
content,
|
content,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if job.Error != nil {
|
if job.Error != nil {
|
||||||
slog.Info("error asking agent,", job.Error)
|
xlog.Info("error asking agent,", job.Error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Info("Response", "response", job.Response)
|
xlog.Info("Response", "response", job.Response)
|
||||||
_, err := s.ChannelMessageSend(m.ChannelID, job.Response)
|
_, err := s.ChannelMessageSend(m.ChannelID, job.Response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Info("error sending message,", err)
|
xlog.Info("error sending message,", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ package connector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/go-github/v61/github"
|
"github.com/google/go-github/v61/github"
|
||||||
"github.com/mudler/local-agent-framework/agent"
|
"github.com/mudler/local-agent-framework/agent"
|
||||||
|
"github.com/mudler/local-agent-framework/xlog"
|
||||||
|
|
||||||
"github.com/sashabaranov/go-openai"
|
"github.com/sashabaranov/go-openai"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -58,10 +59,10 @@ func (g *GithubIssues) Start(a *agent.Agent) {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
slog.Info("Looking into github issues...")
|
xlog.Info("Looking into github issues...")
|
||||||
g.issuesService()
|
g.issuesService()
|
||||||
case <-a.Context().Done():
|
case <-a.Context().Done():
|
||||||
slog.Info("GithubIssues connector is now stopping")
|
xlog.Info("GithubIssues connector is now stopping")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,7 +82,7 @@ func (g *GithubIssues) issuesService() {
|
|||||||
g.repository,
|
g.repository,
|
||||||
&github.IssueListByRepoOptions{})
|
&github.IssueListByRepoOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Info("Error listing issues", err)
|
xlog.Info("Error listing issues", err)
|
||||||
}
|
}
|
||||||
for _, issue := range issues {
|
for _, issue := range issues {
|
||||||
// Do something with the issue
|
// Do something with the issue
|
||||||
@@ -101,7 +102,7 @@ func (g *GithubIssues) issuesService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if userName == user.GetLogin() {
|
if userName == user.GetLogin() {
|
||||||
slog.Info("Ignoring issue opened by the bot")
|
xlog.Info("Ignoring issue opened by the bot")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
messages := []openai.ChatCompletionMessage{
|
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 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 comment.User.GetName() != user.GetLogin() && len(comments)-1 == i {
|
||||||
if strings.Contains(comment.GetBody(), fmt.Sprintf("@%s", user.GetLogin())) {
|
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
|
mustAnswer = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,9 +144,9 @@ func (g *GithubIssues) issuesService() {
|
|||||||
|
|
||||||
if len(comments) == 0 || !botAnsweredAlready {
|
if len(comments) == 0 || !botAnsweredAlready {
|
||||||
// if no comments, or bot didn't answer yet, we must answer
|
// if no comments, or bot didn't answer yet, we must answer
|
||||||
slog.Info("No comments, or bot didn't answer yet")
|
xlog.Info("No comments, or bot didn't answer yet")
|
||||||
slog.Info("Comments:", len(comments))
|
xlog.Info("Comments:", len(comments))
|
||||||
slog.Info("Bot answered already", botAnsweredAlready)
|
xlog.Info("Bot answered already", botAnsweredAlready)
|
||||||
mustAnswer = true
|
mustAnswer = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +158,7 @@ func (g *GithubIssues) issuesService() {
|
|||||||
agent.WithConversationHistory(messages),
|
agent.WithConversationHistory(messages),
|
||||||
)
|
)
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
slog.Error("Error asking", "error", res.Error)
|
xlog.Error("Error asking", "error", res.Error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +170,7 @@ func (g *GithubIssues) issuesService() {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Error creating comment", "error", err)
|
xlog.Error("Error creating comment", "error", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ package connector
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"log/slog"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mudler/local-agent-framework/xlog"
|
||||||
|
|
||||||
"github.com/mudler/local-agent-framework/agent"
|
"github.com/mudler/local-agent-framework/agent"
|
||||||
|
|
||||||
"github.com/slack-go/slack/socketmode"
|
"github.com/slack-go/slack/socketmode"
|
||||||
@@ -61,11 +62,11 @@ func (t *Slack) Start(a *agent.Agent) {
|
|||||||
for evt := range client.Events {
|
for evt := range client.Events {
|
||||||
switch evt.Type {
|
switch evt.Type {
|
||||||
case socketmode.EventTypeConnecting:
|
case socketmode.EventTypeConnecting:
|
||||||
slog.Info("Connecting to Slack with Socket Mode...")
|
xlog.Info("Connecting to Slack with Socket Mode...")
|
||||||
case socketmode.EventTypeConnectionError:
|
case socketmode.EventTypeConnectionError:
|
||||||
slog.Info("Connection failed. Retrying later...")
|
xlog.Info("Connection failed. Retrying later...")
|
||||||
case socketmode.EventTypeConnected:
|
case socketmode.EventTypeConnected:
|
||||||
slog.Info("Connected to Slack with Socket Mode.")
|
xlog.Info("Connected to Slack with Socket Mode.")
|
||||||
case socketmode.EventTypeEventsAPI:
|
case socketmode.EventTypeEventsAPI:
|
||||||
eventsAPIEvent, ok := evt.Data.(slackevents.EventsAPIEvent)
|
eventsAPIEvent, ok := evt.Data.(slackevents.EventsAPIEvent)
|
||||||
if !ok {
|
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
|
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
|
t.channelID != ev.Channel { // If we have a channelID and it's not the same as the event channel
|
||||||
// Skip messages from other channels
|
// 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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +125,7 @@ func (t *Slack) Start(a *agent.Agent) {
|
|||||||
|
|
||||||
// strip our id from the message
|
// strip our id from the message
|
||||||
message = strings.ReplaceAll(message, "<@"+b.UserID+"> ", "")
|
message = strings.ReplaceAll(message, "<@"+b.UserID+"> ", "")
|
||||||
slog.Info("Message", message)
|
xlog.Info("Message", message)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
res := a.Ask(
|
res := a.Ask(
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log/slog"
|
|
||||||
|
"github.com/mudler/local-agent-framework/xlog"
|
||||||
|
|
||||||
. "github.com/mudler/local-agent-framework/agent"
|
. "github.com/mudler/local-agent-framework/agent"
|
||||||
|
|
||||||
@@ -34,20 +35,20 @@ func (a *AgentConfig) availableConnectors() []Connector {
|
|||||||
connectors := []Connector{}
|
connectors := []Connector{}
|
||||||
|
|
||||||
for _, c := range a.Connector {
|
for _, c := range a.Connector {
|
||||||
slog.Info("Set Connector", c)
|
xlog.Info("Set Connector", c)
|
||||||
|
|
||||||
var config map[string]string
|
var config map[string]string
|
||||||
if err := json.Unmarshal([]byte(c.Config), &config); err != nil {
|
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
|
continue
|
||||||
}
|
}
|
||||||
slog.Info("Config", config)
|
xlog.Info("Config", config)
|
||||||
|
|
||||||
switch c.Type {
|
switch c.Type {
|
||||||
case ConnectorTelegram:
|
case ConnectorTelegram:
|
||||||
cc, err := connector.NewTelegramConnector(config)
|
cc, err := connector.NewTelegramConnector(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Info("Error creating telegram connector", err)
|
xlog.Info("Error creating telegram connector", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ package main
|
|||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"log"
|
"log"
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/mudler/local-agent-framework/xlog"
|
||||||
|
|
||||||
"github.com/donseba/go-htmx"
|
"github.com/donseba/go-htmx"
|
||||||
fiber "github.com/gofiber/fiber/v2"
|
fiber "github.com/gofiber/fiber/v2"
|
||||||
"github.com/gofiber/template/html/v2"
|
"github.com/gofiber/template/html/v2"
|
||||||
@@ -79,9 +80,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(db.Database) > 0 && kbdisableIndexing != "true" {
|
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 {
|
if err := db.SaveToStore(); err != nil {
|
||||||
slog.Info("Error storing in the KB", err)
|
xlog.Info("Error storing in the KB", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
|
||||||
|
"github.com/mudler/local-agent-framework/xlog"
|
||||||
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -121,7 +123,7 @@ func getWebPage(url string) (string, error) {
|
|||||||
|
|
||||||
func Sitemap(url string) (res []string, err error) {
|
func Sitemap(url string) (res []string, err error) {
|
||||||
err = sitemap.ParseFromSite(url, func(e sitemap.Entry) 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())
|
content, err := getWebPage(e.GetLocation())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
res = append(res, content)
|
res = append(res, content)
|
||||||
@@ -134,10 +136,10 @@ func Sitemap(url string) (res []string, err error) {
|
|||||||
func WebsiteToKB(website string, chunkSize int, db *InMemoryDatabase) {
|
func WebsiteToKB(website string, chunkSize int, db *InMemoryDatabase) {
|
||||||
content, err := Sitemap(website)
|
content, err := Sitemap(website)
|
||||||
if err != nil {
|
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))
|
xlog.Info("Found pages: ", len(content))
|
||||||
slog.Info("ChunkSize: ", chunkSize)
|
xlog.Info("ChunkSize: ", chunkSize)
|
||||||
|
|
||||||
StringsToKB(db, chunkSize, content...)
|
StringsToKB(db, chunkSize, content...)
|
||||||
}
|
}
|
||||||
@@ -145,9 +147,9 @@ func WebsiteToKB(website string, chunkSize int, db *InMemoryDatabase) {
|
|||||||
func StringsToKB(db *InMemoryDatabase, chunkSize int, content ...string) {
|
func StringsToKB(db *InMemoryDatabase, chunkSize int, content ...string) {
|
||||||
for _, c := range content {
|
for _, c := range content {
|
||||||
chunks := splitParagraphIntoChunks(c, chunkSize)
|
chunks := splitParagraphIntoChunks(c, chunkSize)
|
||||||
slog.Info("chunks: ", len(chunks))
|
xlog.Info("chunks: ", len(chunks))
|
||||||
for _, chunk := range chunks {
|
for _, chunk := range chunks {
|
||||||
slog.Info("Chunk size: ", len(chunk))
|
xlog.Info("Chunk size: ", len(chunk))
|
||||||
db.AddEntry(chunk)
|
db.AddEntry(chunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +157,7 @@ func StringsToKB(db *InMemoryDatabase, chunkSize int, content ...string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := db.SaveToStore(); err != nil {
|
if err := db.SaveToStore(); err != nil {
|
||||||
slog.Info("Error storing in the KB", err)
|
xlog.Info("Error storing in the KB", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
72
xlog/xlog.go
Normal file
72
xlog/xlog.go
Normal file
@@ -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...)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user