Skip to content

Commit a3bf6a6

Browse files
authored
Add some basic logging of config on startup when using stdio (#71)
* Add some basic logging of config on startup when using stdio Closes #70. * Still log address when using SSE transport * Log redacted URLs
1 parent d4109ee commit a3bf6a6

File tree

2 files changed

+43
-9
lines changed

2 files changed

+43
-9
lines changed

cmd/mcp-grafana/main.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"context"
55
"flag"
66
"fmt"
7-
"log"
7+
"log/slog"
88
"os"
99

1010
"github.com/mark3labs/mcp-go/server"
@@ -29,19 +29,21 @@ func newServer() *server.MCPServer {
2929
return s
3030
}
3131

32-
func run(transport, addr string) error {
32+
func run(transport, addr string, logLevel slog.Level) error {
33+
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: logLevel})))
3334
s := newServer()
3435

3536
switch transport {
3637
case "stdio":
3738
srv := server.NewStdioServer(s)
3839
srv.SetContextFunc(mcpgrafana.ComposedStdioContextFunc)
40+
slog.Info("Starting Grafana MCP server using stdio transport")
3941
return srv.Listen(context.Background(), os.Stdin, os.Stdout)
4042
case "sse":
4143
srv := server.NewSSEServer(s,
4244
server.WithSSEContextFunc(mcpgrafana.ComposedSSEContextFunc),
4345
)
44-
log.Printf("SSE server listening on %s", addr)
46+
slog.Info("Starting Grafana MCP server using SSE transport", "address", addr)
4547
if err := srv.Start(addr); err != nil {
4648
return fmt.Errorf("Server error: %v", err)
4749
}
@@ -64,9 +66,18 @@ func main() {
6466
"Transport type (stdio or sse)",
6567
)
6668
addr := flag.String("sse-address", "localhost:8000", "The host and port to start the sse server on")
69+
logLevel := flag.String("log-level", "info", "Log level (debug, info, warn, error)")
6770
flag.Parse()
6871

69-
if err := run(transport, *addr); err != nil {
72+
if err := run(transport, *addr, parseLevel(*logLevel)); err != nil {
7073
panic(err)
7174
}
7275
}
76+
77+
func parseLevel(level string) slog.Level {
78+
var l slog.Level
79+
if err := l.UnmarshalText([]byte(level)); err != nil {
80+
return slog.LevelInfo
81+
}
82+
return l
83+
}

mcpgrafana.go

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package mcpgrafana
33
import (
44
"context"
55
"fmt"
6+
"log/slog"
67
"net/http"
78
"net/url"
89
"os"
@@ -47,6 +48,11 @@ var ExtractGrafanaInfoFromEnv server.StdioContextFunc = func(ctx context.Context
4748
if u == "" {
4849
u = defaultGrafanaURL
4950
}
51+
parsedURL, err := url.Parse(u)
52+
if err != nil {
53+
panic(fmt.Errorf("invalid Grafana URL %s: %w", u, err))
54+
}
55+
slog.Info("Using Grafana configuration", "url", parsedURL.Redacted(), "api_key_set", apiKey != "")
5056
return WithGrafanaURL(WithGrafanaAPIKey(ctx, apiKey), u)
5157
}
5258

@@ -100,22 +106,31 @@ type grafanaClientKey struct{}
100106
var ExtractGrafanaClientFromEnv server.StdioContextFunc = func(ctx context.Context) context.Context {
101107
cfg := client.DefaultTransportConfig()
102108
// Extract transport config from env vars, and set it on the context.
103-
if u, ok := os.LookupEnv(grafanaURLEnvVar); ok {
104-
url, err := url.Parse(u)
109+
var grafanaURL string
110+
var parsedURL *url.URL
111+
var ok bool
112+
var err error
113+
if grafanaURL, ok = os.LookupEnv(grafanaURLEnvVar); ok {
114+
parsedURL, err = url.Parse(grafanaURL)
105115
if err != nil {
106116
panic(fmt.Errorf("invalid %s: %w", grafanaURLEnvVar, err))
107117
}
108-
cfg.Host = url.Host
118+
cfg.Host = parsedURL.Host
109119
// The Grafana client will always prefer HTTPS even if the URL is HTTP,
110120
// so we need to limit the schemes to HTTP if the URL is HTTP.
111-
if url.Scheme == "http" {
121+
if parsedURL.Scheme == "http" {
112122
cfg.Schemes = []string{"http"}
113123
}
124+
} else {
125+
parsedURL, _ = url.Parse(defaultGrafanaURL)
114126
}
115-
if apiKey := os.Getenv(grafanaAPIEnvVar); apiKey != "" {
127+
128+
apiKey := os.Getenv(grafanaAPIEnvVar)
129+
if apiKey != "" {
116130
cfg.APIKey = apiKey
117131
}
118132

133+
slog.Debug("Creating Grafana client", "url", parsedURL.Redacted(), "api_key_set", apiKey != "")
119134
client := client.NewHTTPClientWithConfig(strfmt.Default, cfg)
120135
return context.WithValue(ctx, grafanaClientKey{}, client)
121136
}
@@ -161,7 +176,15 @@ type incidentClientKey struct{}
161176

162177
var ExtractIncidentClientFromEnv server.StdioContextFunc = func(ctx context.Context) context.Context {
163178
grafanaURL, apiKey := urlAndAPIKeyFromEnv()
179+
if grafanaURL == "" {
180+
grafanaURL = defaultGrafanaURL
181+
}
164182
incidentURL := fmt.Sprintf("%s/api/plugins/grafana-incident-app/resources/api/v1/", grafanaURL)
183+
parsedURL, err := url.Parse(incidentURL)
184+
if err != nil {
185+
panic(fmt.Errorf("invalid incident URL %s: %w", incidentURL, err))
186+
}
187+
slog.Debug("Creating Incident client", "url", parsedURL.Redacted(), "api_key_set", apiKey != "")
165188
client := incident.NewClient(incidentURL, apiKey)
166189
return context.WithValue(ctx, incidentClientKey{}, client)
167190
}

0 commit comments

Comments
 (0)