From 5db3463846ed762a613e79a852c20df9bcc5c877 Mon Sep 17 00:00:00 2001 From: MrMarble <4268580+MrMarble@users.noreply.github.com> Date: Sat, 25 Jul 2020 15:54:29 +0200 Subject: [PATCH] :sparkles: Added features logs --- docker.go | 27 +++++++++++++++++++++++++++ handlers.go | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- telegram.go | 11 ++++++++--- utils.go | 5 +++++ 4 files changed, 87 insertions(+), 6 deletions(-) diff --git a/docker.go b/docker.go index afed99f..59c0aa9 100644 --- a/docker.go +++ b/docker.go @@ -2,6 +2,7 @@ package main import ( "context" + "io" "regexp" "time" @@ -70,6 +71,32 @@ func (d *Docker) inspect(containerID string) (*types.ContainerJSON, error) { return &container, nil } +func (d *Docker) logs(containerID string, tail string) ([]string, error) { + var ( + bytes []byte = make([]byte, 3000) // Telegram message length limit + logs []string = nil + err error = nil + ) + if tail != "all" && !isNumber(tail) { + tail = "10" + } + logsReader, err := d.cli.ContainerLogs(d.ctx, containerID, types.ContainerLogsOptions{Tail: tail, ShowStderr: true, ShowStdout: true}) + defer logsReader.Close() + + if err != nil { + log.Fatal().Str("module", "docker").Str("containerID", containerID).Err(err).Msg("error getting container logs") + return nil, err + } + for { + numBytes, err := logsReader.Read(bytes) + logs = append(logs, string(bytes[:numBytes])) + if err == io.EOF { + break + } + } + return logs, nil +} + func (d *Docker) isValidID(containerID string) bool { re := regexp.MustCompile(`(?m)^[A-Fa-f0-9]{10,12}$`) return re.MatchString(containerID) diff --git a/handlers.go b/handlers.go index 1880f08..bb2011b 100644 --- a/handlers.go +++ b/handlers.go @@ -122,6 +122,36 @@ func (t *Telegram) handleStacks(m *tb.Message) { t.send(m.Chat, strings.Join(resultMsg, "\n\n")) } +func (t *Telegram) handleLogs(m *tb.Message) { + if !t.isSuperAdmin(m.Sender) { + return + } + payload := strings.Split(m.Payload, " ") + containerID := payload[0] + if containerID == "" || !docker.isValidID(containerID) { + t.reply(m, "Choose a container", makeContainerMenu(t, types.ContainerListOptions{All: true}, "logs")) + } else { + var tail string = "10" + if len(payload) > 1 { + tail = payload[1] + } + logs, err := docker.logs(containerID, tail) + + if err != nil { + t.reply(m, err.Error()) + return + } + for index, chunk := range logs { + if index == 0 { + t.reply(m, fmt.Sprintf("%v", chunk), tb.ModeHTML) + } else { + t.send(m.Chat, fmt.Sprintf("%v", chunk), tb.ModeHTML) + } + time.Sleep(100 * time.Millisecond) + } + } +} + func (t *Telegram) handleCallback(c *tb.Callback) { parts := strings.Split(c.Data, ":") instruction := parts[0] @@ -139,11 +169,11 @@ func (t *Telegram) handleCallback(c *tb.Callback) { case "inspect": container, err := docker.inspect(payload) if err != nil { - callbackResponse(t, c, err, payload, fmt.Sprintf("%v", payload)) + callbackResponse(t, c, err, payload, "") } else { response, err := formatStruct(container) if err != nil { - callbackResponse(t, c, err, payload, fmt.Sprintf("%v", response)) + callbackResponse(t, c, err, payload, "") return } for index, chunk := range chunkString(response, 300) { @@ -155,6 +185,20 @@ func (t *Telegram) handleCallback(c *tb.Callback) { time.Sleep(250 * time.Millisecond) } } - + case "logs": + logs, err := docker.logs(payload, "10") + if err != nil { + callbackResponse(t, c, err, payload, "") + return + } + for index, chunk := range logs { + if index == 0 { + callbackResponse(t, c, err, payload, fmt.Sprintf("%v", chunk)) + } + if index != 0 && chunk != "" { + t.send(c.Message.Chat, fmt.Sprintf("%v", chunk), tb.ModeHTML) + } + time.Sleep(100 * time.Millisecond) + } } } diff --git a/telegram.go b/telegram.go index 95b9448..c7025be 100644 --- a/telegram.go +++ b/telegram.go @@ -82,18 +82,18 @@ func (t *Telegram) registerHandlers() { Handler: t.handleStop, Cmd: "stop", Aliases: []string{"down"}, - Description: "Stop a running container", + Description: "Stop a running container. ", }, { Handler: t.handleStartContainer, Cmd: "run", - Description: "Start a stopped container", + Description: "Start a stopped container. ", }, { Handler: t.handleInspect, Cmd: "inspect", Aliases: []string{"describe"}, - Description: "Start a stopped container", + Description: "Inspect a container. ", }, { Handler: t.handleStacks, @@ -101,6 +101,11 @@ func (t *Telegram) registerHandlers() { Aliases: []string{"lss", "liststacks"}, Description: "Lists all compose stacks", }, + { + Handler: t.handleLogs, + Cmd: "logs", + Description: "Shows container logs. ", + }, } for _, command := range botCommands { botCommandList = append(botCommandList, tb.Command{ diff --git a/utils.go b/utils.go index 969157d..8947f60 100644 --- a/utils.go +++ b/utils.go @@ -24,6 +24,11 @@ func parseInt64(s string) (int64, error) { return int64(i), nil } +func isNumber(s string) bool { + _, err := strconv.Atoi(s) + return err == nil +} + func parseList(options types.ContainerListOptions) []string { containers := docker.list(options) if len(containers) == 0 {