add better logs
This commit is contained in:
@@ -4,24 +4,43 @@ import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var logsCmd = &cobra.Command{
|
||||
Use: "logs",
|
||||
Short: "Open the Dozzle log viewer in the browser",
|
||||
Use: "logs [container]",
|
||||
Short: "Open Dozzle in the browser, optionally deep-linking to a container",
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cfg, _, _, err := setup()
|
||||
cfg, client, _, err := setup()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Derive logs URL from Portainer URL (same base domain)
|
||||
// e.g. https://portainer.home.jens.pub → https://logs.home.jens.pub
|
||||
logsURL := deriveLogsURL(cfg.Portainer.URL)
|
||||
fmt.Printf("Opening %s\n", logsURL)
|
||||
return openBrowser(logsURL)
|
||||
logsBase := deriveLogsURL(cfg.Portainer.URL)
|
||||
|
||||
if len(args) == 0 {
|
||||
fmt.Printf("Opening %s\n", logsBase)
|
||||
return openBrowser(logsBase)
|
||||
}
|
||||
|
||||
containerName := args[0]
|
||||
id, err := client.FindContainer(containerName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Dozzle uses a short ID (first 12 chars)
|
||||
shortID := id
|
||||
if len(shortID) > 12 {
|
||||
shortID = shortID[:12]
|
||||
}
|
||||
|
||||
url := logsBase + "/container/" + shortID
|
||||
fmt.Printf("Opening %s\n", url)
|
||||
return openBrowser(url)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -30,24 +49,17 @@ func init() {
|
||||
}
|
||||
|
||||
func deriveLogsURL(portainerURL string) string {
|
||||
domain := stripScheme(portainerURL)
|
||||
// Replace "portainer." prefix with "logs."
|
||||
return fmt.Sprintf("https://logs.%s", domainFromURL(portainerURL))
|
||||
}
|
||||
|
||||
func domainFromURL(u string) string {
|
||||
// Strip scheme and find domain after first dot
|
||||
u = stripScheme(u)
|
||||
for i, c := range u {
|
||||
if c == '.' {
|
||||
return u[i+1:]
|
||||
}
|
||||
if idx := strings.Index(domain, "."); idx != -1 {
|
||||
return "https://logs." + domain[idx+1:]
|
||||
}
|
||||
return u
|
||||
return "https://logs." + domain
|
||||
}
|
||||
|
||||
func stripScheme(u string) string {
|
||||
for _, prefix := range []string{"https://", "http://"} {
|
||||
if len(u) > len(prefix) && u[:len(prefix)] == prefix {
|
||||
if strings.HasPrefix(u, prefix) {
|
||||
return u[len(prefix):]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,29 @@ type StackFile struct {
|
||||
StackFileContent string `json:"StackFileContent"`
|
||||
}
|
||||
|
||||
type Container struct {
|
||||
ID string `json:"Id"`
|
||||
Names []string `json:"Names"`
|
||||
}
|
||||
|
||||
// FindContainer returns the container ID for a given name (e.g. "seerr").
|
||||
// Docker container names have a leading slash, so "/seerr" matches "seerr".
|
||||
func (c *Client) FindContainer(name string) (string, error) {
|
||||
var containers []Container
|
||||
if err := c.get(fmt.Sprintf("/api/endpoints/%d/docker/containers/json", c.endpointID), &containers); err != nil {
|
||||
return "", err
|
||||
}
|
||||
want := "/" + name
|
||||
for _, ct := range containers {
|
||||
for _, n := range ct.Names {
|
||||
if n == want {
|
||||
return ct.ID, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("container %q not found", name)
|
||||
}
|
||||
|
||||
func New(baseURL, token, endpointName string) (*Client, error) {
|
||||
c := &Client{
|
||||
baseURL: strings.TrimRight(baseURL, "/"),
|
||||
|
||||
Reference in New Issue
Block a user