LoginSignup
2
1

More than 3 years have passed since last update.

Go言語 コンソールモードでコンソール上にグラフ、ボタン、スクロールテキストを表示するtermdashの紹介

Posted at

概要

通常コンソールにはテキストしか表示できないと思い込んでいました。紹介するtermdashを使えばコンソール上にGUIもどきのものが表示できます。

機能

下記の画像はデモをWindowsで実行したものです。

image.png

次が画面の中央にある白いボタンのsparklinesをマウスでクリックしたときの画面です

image.png

下記のURLではグラフが時間変化する動画が見られます。

  • Github URL
  • レイアウト
  • Widget
    • BarChart 棒グラフ (画像の右上)
    • Button ボタン (画像の中央4ボタンと右下の2ボタン)
    • Donut ドーナツグラフ (画像のBarChartの下)
    • Gauge ゲージ (画像の中央の緑の帯)
    • LineChart グラフ(画像の下、マウスによるズーム機能)
    • SegmentDisplay 未調査
    • Sparkline ミニグラフ (画像の中央)
    • Text  (画像の中央)
      • スクロール
        • マウスやキーボードでスクロールできます。
      • テキストの折り返し
      • はみ出し分を省略

各 OS上での実行

  • Windows 上記画像の通り問題なし
    • 日本語や中国語などを表示するときはchcp 65001でUTF-8にしないと画面が乱れる
  • Mac ほぼ問題はなかったが Sparklineに横筋が入っていた
  • Linux  (ubuntu 18.04)
    • Linux画面を直接操作することはないので以下のsshで試しました。
    • Mac ssh ではMac上と同じでした
    • Windows (おすすめはgit bashのssh)
      • git bash のssh
        • 一番良かった
        • ボタンも押せます 
        • sparklineの表示で塗りつぶされていない四角文字がでる(気にしなければ問題ない)
        • Scroll textでスクロールの特殊文字が表示されない
      • putty
        • グラフは出たが 枠の罫線が乱れている
        • ボタンが押せない
      • openssh
        • 時間変化させたグラフ等が乱れる。
        • ボタンが押せない
        • 一部枠の罫線が乱れる
      • WSL(ubuntu 18.04) のssh
        • LineChartが乱れる
        • Donutが乱れる
        • 中央の白いボタンが出ない
        • 右下のボタンは表示されて、クリックも出来る。

Scroll textが2つのログコンソール画面の実装

次のような画面です。左がFatalログで右がInformationログです。下記の画面は右側をクリックしたので枠の色が黄色?になっていますのでマウスの中ボタンやキーボードのカーソルキーで上下にスクロールできます。ログの文字が折り返されたら画面を横に広げればリサイズされます。 Fatalの時刻は赤にして、Informationはシアンにしました。

image.png

ソースコード

デモのソースを簡単に改造しただけです。Fatalかどうかは乱数によって決めました。実際はログファイルやデータベース、ネットワークから取得すると思います。

container.SplitVerticalを使って画面を縦に2分割しました。

main.go
package main

import (
    "context"
    "fmt"
    "math/rand"
    "time"

    "github.com/mum4k/termdash"
    "github.com/mum4k/termdash/cell"
    "github.com/mum4k/termdash/container"
    "github.com/mum4k/termdash/linestyle"
    "github.com/mum4k/termdash/terminal/termbox"
    "github.com/mum4k/termdash/terminal/terminalapi"
    "github.com/mum4k/termdash/widgets/text"
)

func writeLines(ctx context.Context, fatal, info *text.Text, delay time.Duration) {
    s := rand.NewSource(time.Now().Unix())
    r := rand.New(s)
    ticker := time.NewTicker(delay)
    defer ticker.Stop()
    fatalCount := 0
    infoCount := 0
    for {
        select {
        case <-ticker.C:
            var err error
            d := time.Now().Format("03:04:05")
            i := r.Intn(3)
            if i == 0 {
                fatal.Write(d, text.WriteCellOpts(cell.FgColor(cell.ColorRed)))
                if err == nil {
                    fatalCount++
                    log := fmt.Sprintf(" %d fatal fatal fatal\n", fatalCount)
                    err = fatal.Write(log)
                }
            } else {
                err = info.Write(d, text.WriteCellOpts(cell.FgColor(cell.ColorCyan)))
                if err == nil {
                    infoCount++
                    log := fmt.Sprintf(" %d information information information\n", infoCount)
                    err = info.Write(log)
                }
            }
            if err != nil {
                panic(err)
            }
        case <-ctx.Done():
            return
        }
    }
}

func main() {
    t, err := termbox.New()
    if err != nil {
        panic(err)
    }
    defer t.Close()

    ctx, cancel := context.WithCancel(context.Background())

    rolledFatal, err := text.New(text.RollContent(), text.WrapAtWords())
    if err != nil {
        panic(err)
    }
    rolledInfo, err := text.New(text.RollContent(), text.WrapAtWords())
    if err != nil {
        panic(err)
    }
    go writeLines(ctx, rolledFatal, rolledInfo, 1*time.Second)

    c, err := container.New(
        t,
        container.Border(linestyle.Light),
        container.BorderTitle("PRESS Q TO QUIT"),
        container.SplitVertical(
            container.Left(
                container.Border(linestyle.Light),
                container.BorderTitle("  Fatal ログ"),
                container.PlaceWidget(rolledFatal),
            ),
            container.Right(
                container.Border(linestyle.Light),
                container.BorderTitle("  Information ログ"),
                container.PlaceWidget(rolledInfo),
            ),
        ),
    )
    if err != nil {
        panic(err)
    }

    quitter := func(k *terminalapi.Keyboard) {
        if k.Key == 'q' || k.Key == 'Q' {
            cancel()
        }
    }

    if err := termdash.Run(ctx, t, c, termdash.KeyboardSubscriber(quitter)); err != nil {
        panic(err)
    }
}

まとめ

サーバー系のモニタ画面に使えるのではないかと思います。 まさかコンソールでマウスが使えるとは思いませんでした。
各Layout, Widgetの使い方をQIITAに載せて頂けると嬉しいです。
git bashのsshよりもっと最適なWindowsのSSHソフトが有ったら教えてほしいです。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1