From cb978f760fc93cedb7bebea91e8a2fe9c780b79b Mon Sep 17 00:00:00 2001 From: Benson Wong Date: Sun, 8 Dec 2024 21:26:22 -0800 Subject: [PATCH] add web interface to /logs --- README.md | 15 +++++---- proxy/html/logs.html | 53 +++++++++++++++++++++++++++++++ proxy/proxymanager_loghandlers.go | 34 ++++++++++++++++---- 3 files changed, 89 insertions(+), 13 deletions(-) create mode 100644 proxy/html/logs.html diff --git a/README.md b/README.md index cd15d4c..ce690bb 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ ![llama-swap header image](header.jpeg) -llama-swap is a golang server that automatically swaps the llama.cpp server on demand. Since [llama.cpp's server](https://github.com/ggerganov/llama.cpp/tree/master/examples/server) can't swap models, let's swap the server instead! +# Introduction +llama-swap is an OpenAI API compatible server that gives you complete control over how you use your hardware. It automatically swaps to the configuration of your choice for serving a model. Since [llama.cpp's server](https://github.com/ggerganov/llama.cpp/tree/master/examples/server) can't swap models, let's swap the server instead! Features: @@ -83,22 +84,22 @@ More [examples](examples/README.md) are available for different use cases. ## Monitoring Logs -The `/logs` endpoint is available to monitor what llama-swap is doing. It will send the last 10KB of logs. Useful for monitoring the output of llama-server. It also supports streaming of logs. +Open the `http:///logs` with your browser to get a web interface with streaming logs. -Usage: +Of course, CLI access is also supported: ``` # sends up to the last 10KB of logs curl http://host/logs' -# streams logs using chunk encoding +# streams logs curl -Ns 'http://host/logs/stream' +# stream and filter logs with linux pipes +curl -Ns http://host/logs/stream | grep 'eval time' + # skips history and just streams new log entries curl -Ns 'http://host/logs/stream?no-history' - -# streams logs using Server Sent Events -curl -Ns 'http://host/logs/streamSSE' ``` ## Systemd Unit Files diff --git a/proxy/html/logs.html b/proxy/html/logs.html new file mode 100644 index 0000000..49026f1 --- /dev/null +++ b/proxy/html/logs.html @@ -0,0 +1,53 @@ + + + + + + Logs + + + +
Waiting for logs...
+
+ + + + \ No newline at end of file diff --git a/proxy/proxymanager_loghandlers.go b/proxy/proxymanager_loghandlers.go index 8946470..fc2ac4d 100644 --- a/proxy/proxymanager_loghandlers.go +++ b/proxy/proxymanager_loghandlers.go @@ -1,19 +1,41 @@ package proxy import ( + "embed" "fmt" "net/http" + "strings" "github.com/gin-gonic/gin" ) +//go:embed html/logs.html +var logsHTML []byte + +// make sure embed is kept there by the IDE auto-package importer +var _ = embed.FS{} + func (pm *ProxyManager) sendLogsHandlers(c *gin.Context) { - c.Header("Content-Type", "text/plain") - history := pm.logMonitor.GetHistory() - _, err := c.Writer.Write(history) - if err != nil { - c.AbortWithError(http.StatusInternalServerError, err) - return + + accept := c.GetHeader("Accept") + if strings.Contains(accept, "text/html") { + // Set the Content-Type header to text/html + c.Header("Content-Type", "text/html") + + // Write the embedded HTML content to the response + _, err := c.Writer.Write(logsHTML) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to write response: %v", err)) + return + } + } else { + c.Header("Content-Type", "text/plain") + history := pm.logMonitor.GetHistory() + _, err := c.Writer.Write(history) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, err) + return + } } }