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 {