From d1e789f2cff3ffcf9c1c14c15109397119350e13 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 27 Nov 2020 10:33:17 +0000 Subject: Terminate on SIGHUP --- internal/io/signal/signal.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/internal/io/signal/signal.go b/internal/io/signal/signal.go index 3785d71..9401707 100644 --- a/internal/io/signal/signal.go +++ b/internal/io/signal/signal.go @@ -4,6 +4,7 @@ import ( "context" "os" gosignal "os/signal" + "syscall" "time" "github.com/mimecast/dtail/internal/io/logger" @@ -11,26 +12,31 @@ import ( // StatsCh returns a channel for "please print stats" signalling. func InterruptCh(ctx context.Context) <-chan struct{} { - sigCh := make(chan os.Signal) - gosignal.Notify(sigCh, os.Interrupt) + sigIntCh := make(chan os.Signal) + gosignal.Notify(sigIntCh, os.Interrupt) + + sigOtherCh := make(chan os.Signal) + gosignal.Notify(sigOtherCh, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGQUIT) statsCh := make(chan struct{}) go func() { for { select { - case <-sigCh: + case <-sigIntCh: select { case statsCh <- struct{}{}: - logger.Info("Hit Ctrl+C twice to exit") + logger.Info("Hint: Hit Ctrl+C twice to exit") select { - case <-sigCh: + case <-sigIntCh: os.Exit(0) case <-time.After(time.Second): } default: - // Stats currently already printed. + // Stats already printed. } + case <-sigOtherCh: + os.Exit(0) case <-ctx.Done(): return } -- cgit v1.2.3 From c4d18500da897c960a43091ff55caee63db0f7df Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 27 Nov 2020 10:41:38 +0000 Subject: new dev version --- internal/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/version/version.go b/internal/version/version.go index 36ef62c..750aaf2 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -13,7 +13,7 @@ const ( // Version of DTail. Version string = "3.1.0" // Additional information for DTail - Additional string = "develop" + Additional string = "develop-II" // ProtocolCompat -ibility version. ProtocolCompat string = "3" ) -- cgit v1.2.3 From 57527ff880f79c5ee18ac016deed11ce21d6b7ef Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 27 Nov 2020 14:47:43 +0000 Subject: First Ctrl+C will print out stats, a second Ctrl+C within 3s will terminate dtail --- internal/clients/baseclient.go | 2 +- internal/clients/client.go | 2 +- internal/clients/maprclient.go | 2 +- internal/clients/stats.go | 26 ++++++++++++++++++++++---- internal/io/signal/signal.go | 11 ++++------- 5 files changed, 29 insertions(+), 14 deletions(-) diff --git a/internal/clients/baseclient.go b/internal/clients/baseclient.go index d8d4fde..69055a3 100644 --- a/internal/clients/baseclient.go +++ b/internal/clients/baseclient.go @@ -66,7 +66,7 @@ func (c *baseClient) makeConnections(maker maker) { c.stats = newTailStats(len(c.connections)) } -func (c *baseClient) Start(ctx context.Context, statsCh <-chan struct{}) (status int) { +func (c *baseClient) Start(ctx context.Context, statsCh <-chan string) (status int) { // Periodically check for unknown hosts, and ask the user whether to trust them or not. go c.hostKeyCallback.PromptAddHosts(ctx) // Print client stats every time something on statsCh is recieved. diff --git a/internal/clients/client.go b/internal/clients/client.go index eb8452d..4a547e8 100644 --- a/internal/clients/client.go +++ b/internal/clients/client.go @@ -4,5 +4,5 @@ import "context" // Client is the interface for the end user command line client. type Client interface { - Start(ctx context.Context, statsCh <-chan struct{}) int + Start(ctx context.Context, statsCh <-chan string) int } diff --git a/internal/clients/maprclient.go b/internal/clients/maprclient.go index 149129d..6aadd6b 100644 --- a/internal/clients/maprclient.go +++ b/internal/clients/maprclient.go @@ -94,7 +94,7 @@ func NewMaprClient(args Args, queryStr string, maprClientMode MaprClientMode) (* } // Start starts the mapreduce client. -func (c *MaprClient) Start(ctx context.Context, statsCh <-chan struct{}) (status int) { +func (c *MaprClient) Start(ctx context.Context, statsCh <-chan string) (status int) { go c.periodicReportResults(ctx) status = c.baseClient.Start(ctx, statsCh) diff --git a/internal/clients/stats.go b/internal/clients/stats.go index e7eabd8..d5bcd2d 100644 --- a/internal/clients/stats.go +++ b/internal/clients/stats.go @@ -33,16 +33,18 @@ func newTailStats(connectionsTotal int) *stats { // Start starts printing client connection stats every time a signal is recieved or // connection count has changed. -func (s *stats) Start(ctx context.Context, throttleCh, statsCh <-chan struct{}) { +func (s *stats) Start(ctx context.Context, throttleCh <-chan struct{}, statsCh <-chan string) { var connectedLast int for { var force bool + var messages []string select { - case <-statsCh: + case message := <-statsCh: + messages = append(messages, message) force = true - case <-time.After(time.Second * 2): + case <-time.After(time.Second * 10): case <-ctx.Done(): return } @@ -56,7 +58,14 @@ func (s *stats) Start(ctx context.Context, throttleCh, statsCh <-chan struct{}) continue } - logger.Info(s.statsLine(connected, newConnections, throttle)) + stats := s.statsLine(connected, newConnections, throttle) + switch force { + case true: + messages = append(messages, fmt.Sprintf("Connection stats: %s", stats)) + s.forcePrintStats(messages) + default: + logger.Info(stats) + } connectedLast = connected s.mutex.Lock() @@ -65,6 +74,15 @@ func (s *stats) Start(ctx context.Context, throttleCh, statsCh <-chan struct{}) } } +func (s *stats) forcePrintStats(messages []string) { + logger.Pause() + for _, message := range messages { + fmt.Println(fmt.Sprintf("\t%s", message)) + } + time.Sleep(time.Second * 3) + logger.Resume() +} + func (s *stats) statsLine(connected, newConnections int, throttle int) string { percConnected := percentOf(float64(s.connectionsTotal), float64(connected)) diff --git a/internal/io/signal/signal.go b/internal/io/signal/signal.go index 9401707..06abb0b 100644 --- a/internal/io/signal/signal.go +++ b/internal/io/signal/signal.go @@ -6,31 +6,28 @@ import ( gosignal "os/signal" "syscall" "time" - - "github.com/mimecast/dtail/internal/io/logger" ) // StatsCh returns a channel for "please print stats" signalling. -func InterruptCh(ctx context.Context) <-chan struct{} { +func InterruptCh(ctx context.Context) <-chan string { sigIntCh := make(chan os.Signal) gosignal.Notify(sigIntCh, os.Interrupt) sigOtherCh := make(chan os.Signal) gosignal.Notify(sigOtherCh, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGQUIT) - statsCh := make(chan struct{}) + statsCh := make(chan string) go func() { for { select { case <-sigIntCh: select { - case statsCh <- struct{}{}: - logger.Info("Hint: Hit Ctrl+C twice to exit") + case statsCh <- "Hint: Hit Ctrl+C again to exit": select { case <-sigIntCh: os.Exit(0) - case <-time.After(time.Second): + case <-time.After(time.Second * 3): } default: // Stats already printed. -- cgit v1.2.3 From d188da703ee107459010300397db4510a2de2c32 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 27 Nov 2020 14:57:36 +0000 Subject: use global interrupt timeout setting for interrupt timeout --- internal/clients/stats.go | 9 +++++---- internal/config/config.go | 3 +++ internal/io/signal/signal.go | 4 +++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/internal/clients/stats.go b/internal/clients/stats.go index d5bcd2d..17343b5 100644 --- a/internal/clients/stats.go +++ b/internal/clients/stats.go @@ -8,6 +8,7 @@ import ( "sync" "time" + "github.com/mimecast/dtail/internal/config" "github.com/mimecast/dtail/internal/io/logger" ) @@ -62,7 +63,7 @@ func (s *stats) Start(ctx context.Context, throttleCh <-chan struct{}, statsCh < switch force { case true: messages = append(messages, fmt.Sprintf("Connection stats: %s", stats)) - s.forcePrintStats(messages) + s.printStatsOnInterrupt(messages) default: logger.Info(stats) } @@ -74,12 +75,12 @@ func (s *stats) Start(ctx context.Context, throttleCh <-chan struct{}, statsCh < } } -func (s *stats) forcePrintStats(messages []string) { +func (s *stats) printStatsOnInterrupt(messages []string) { logger.Pause() for _, message := range messages { - fmt.Println(fmt.Sprintf("\t%s", message)) + fmt.Println(fmt.Sprintf(" %s", message)) } - time.Sleep(time.Second * 3) + time.Sleep(time.Second * time.Duration(config.InterruptTimeoutS)) logger.Resume() } diff --git a/internal/config/config.go b/internal/config/config.go index dc96d6b..276ddcf 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -15,6 +15,9 @@ const ScheduleUser string = "DTAIL-SCHEDULE" // ContinuousUser is used for non-interactive continuous mapreduce queries. const ContinuousUser string = "DTAIL-CONTINUOUS" +// InterruptTimeoutS is used to terminate DTail when Ctrl+C was pressed twice within a given interval. +const InterruptTimeoutS int = 3 + // Client holds a DTail client configuration. var Client *ClientConfig diff --git a/internal/io/signal/signal.go b/internal/io/signal/signal.go index 06abb0b..27c7852 100644 --- a/internal/io/signal/signal.go +++ b/internal/io/signal/signal.go @@ -6,6 +6,8 @@ import ( gosignal "os/signal" "syscall" "time" + + "github.com/mimecast/dtail/internal/config" ) // StatsCh returns a channel for "please print stats" signalling. @@ -27,7 +29,7 @@ func InterruptCh(ctx context.Context) <-chan string { select { case <-sigIntCh: os.Exit(0) - case <-time.After(time.Second * 3): + case <-time.After(time.Second * time.Duration(config.InterruptTimeoutS)): } default: // Stats already printed. -- cgit v1.2.3 From 4c76bc992793e630da492d1b51dffa1c0396cb30 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Tue, 8 Dec 2020 14:32:29 +0000 Subject: make lint and vet happy --- Makefile | 4 ++-- go.mod | 2 +- go.sum | 14 ++++++++++++++ internal/clients/handlers/healthhandler.go | 2 ++ internal/config/server.go | 1 + internal/io/signal/signal.go | 2 +- internal/mapr/server/aggregate.go | 1 + internal/regex/flag.go | 2 ++ internal/regex/regex.go | 7 +++++++ internal/server/continuous.go | 2 +- internal/server/handlers/controlhandler.go | 2 ++ internal/server/handlers/serverhandler.go | 2 ++ internal/server/scheduler.go | 2 +- 13 files changed, 37 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 8e3d608..6552f0c 100644 --- a/Makefile +++ b/Makefile @@ -24,8 +24,8 @@ vet: lint: ${GO} get golang.org/x/lint/golint find . -type d | while read dir; do \ - echo ${GOPATH}/bin/golint $$dir; \ - ${GOPATH}/bin/golint $$dir; \ + echo golint $$dir; \ + golint $$dir; \ done test: ${GO} test ./... -v diff --git a/go.mod b/go.mod index e95da7d..863e417 100644 --- a/go.mod +++ b/go.mod @@ -6,5 +6,5 @@ require ( github.com/DataDog/zstd v1.4.5 golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect - golang.org/x/sys v0.0.0-20200812155832-6a926be9bd1d // indirect + golang.org/x/tools v0.0.0-20201208062317-e652b2f42cc7 // indirect ) diff --git a/go.sum b/go.sum index 00c6f54..2487cf1 100644 --- a/go.sum +++ b/go.sum @@ -2,10 +2,12 @@ github.com/DataDog/zstd v1.4.4 h1:+IawcoXhCBylN7ccwdwf8LOH2jKq7NavGpEPanrlTzE= github.com/DataDog/zstd v1.4.4/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 h1:sKJQZMuxjOAR/Uo2LBfU90onWEf1dF4C+0hPJCc9Mpc= golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/lint v0.0.0-20200130185559-910be7a94367 h1:0IiAsCRByjO2QjX7ZPkw5oU9x+n1YqRL802rjC0c3Aw= @@ -13,15 +15,27 @@ golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200812155832-6a926be9bd1d h1:QQrM/CCYEzTs91GZylDCQjGHudbPTxF/1fvXdVh5lMo= golang.org/x/sys v0.0.0-20200812155832-6a926be9bd1d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7 h1:EBZoQjiKKPaLbPrbpssUfuHtwM6KV/vb4U85g/cigFY= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20201208062317-e652b2f42cc7 h1:2OSu5vYyX4LVqZAtqZXnFEcN26SDKIJYlEVIRl1tj8U= +golang.org/x/tools v0.0.0-20201208062317-e652b2f42cc7/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/clients/handlers/healthhandler.go b/internal/clients/handlers/healthhandler.go index 95693ab..08ed137 100644 --- a/internal/clients/handlers/healthhandler.go +++ b/internal/clients/handlers/healthhandler.go @@ -45,10 +45,12 @@ func (h *HealthHandler) Status() int { return h.status } +// Done returns done channel of the handler. func (h *HealthHandler) Done() <-chan struct{} { return h.done.Done() } +// Shutdown the handler. func (h *HealthHandler) Shutdown() { h.done.Shutdown() } diff --git a/internal/config/server.go b/internal/config/server.go index db12cec..dc0d587 100644 --- a/internal/config/server.go +++ b/internal/config/server.go @@ -61,6 +61,7 @@ type ServerConfig struct { Continuous []Continuous `json:",omitempty"` } +// ServerRelaxedAuthEnable should be used for development and testing purposes only. var ServerRelaxedAuthEnable bool // Create a new default server configuration. diff --git a/internal/io/signal/signal.go b/internal/io/signal/signal.go index 27c7852..500c530 100644 --- a/internal/io/signal/signal.go +++ b/internal/io/signal/signal.go @@ -10,7 +10,7 @@ import ( "github.com/mimecast/dtail/internal/config" ) -// StatsCh returns a channel for "please print stats" signalling. +// InterruptCh returns a channel for "please print stats" signalling. func InterruptCh(ctx context.Context) <-chan string { sigIntCh := make(chan os.Signal) gosignal.Notify(sigIntCh, os.Interrupt) diff --git a/internal/mapr/server/aggregate.go b/internal/mapr/server/aggregate.go index cd59b63..28bb074 100644 --- a/internal/mapr/server/aggregate.go +++ b/internal/mapr/server/aggregate.go @@ -80,6 +80,7 @@ func NewAggregate(queryStr string) (*Aggregate, error) { return &a, nil } +// Shutdown the aggregation engine. func (a *Aggregate) Shutdown() { a.Flush() a.done.Shutdown() diff --git a/internal/regex/flag.go b/internal/regex/flag.go index d3ff712..396bda0 100644 --- a/internal/regex/flag.go +++ b/internal/regex/flag.go @@ -2,6 +2,7 @@ package regex import "fmt" +// Flag for regex. type Flag int const ( @@ -15,6 +16,7 @@ const ( Noop Flag = iota ) +// NewFlag returns a new regex flag. func NewFlag(str string) (Flag, error) { switch str { case "default": diff --git a/internal/regex/regex.go b/internal/regex/regex.go index f668c38..2561659 100644 --- a/internal/regex/regex.go +++ b/internal/regex/regex.go @@ -8,6 +8,7 @@ import ( "github.com/mimecast/dtail/internal/io/logger" ) +// Regex for filtering lines. type Regex struct { // The original regex string regexStr string @@ -24,6 +25,7 @@ func (r Regex) String() string { r.regexStr, r.flags, r.initialized, r.re == nil) } +// NewNoop is a noop regex (doing nothing). func NewNoop() Regex { return Regex{ flags: []Flag{Noop}, @@ -31,6 +33,7 @@ func NewNoop() Regex { } } +// New returns a new regex object. func New(regexStr string, flag Flag) (Regex, error) { if regexStr == "" || regexStr == "." || regexStr == ".*" { return NewNoop(), nil @@ -59,6 +62,7 @@ func new(regexStr string, flags []Flag) (Regex, error) { return r, nil } +// Match a byte string. func (r Regex) Match(bytes []byte) bool { switch r.flags[0] { case Default: @@ -72,6 +76,7 @@ func (r Regex) Match(bytes []byte) bool { } } +// MatchString matches a string. func (r Regex) MatchString(str string) bool { switch r.flags[0] { case Default: @@ -85,6 +90,7 @@ func (r Regex) MatchString(str string) bool { } } +// Serialize the regex. func (r Regex) Serialize() string { var flags []string for _, flag := range r.flags { @@ -98,6 +104,7 @@ func (r Regex) Serialize() string { return fmt.Sprintf("regex:%s %s", strings.Join(flags, ","), r.regexStr) } +// Deserialize the regex. func Deserialize(str string) (Regex, error) { // Get regex string s := strings.SplitN(str, " ", 2) diff --git a/internal/server/continuous.go b/internal/server/continuous.go index 583d136..f75c732 100644 --- a/internal/server/continuous.go +++ b/internal/server/continuous.go @@ -92,7 +92,7 @@ func (c *continuous) runJob(ctx context.Context, job config.Continuous) { } logger.Info(fmt.Sprintf("Starting job %s", job.Name)) - status := client.Start(jobCtx, make(chan struct{})) + status := client.Start(jobCtx, make(chan string)) logMessage := fmt.Sprintf("Job exited with status %d", status) if status != 0 { diff --git a/internal/server/handlers/controlhandler.go b/internal/server/handlers/controlhandler.go index 9a8eb75..8cc5a40 100644 --- a/internal/server/handlers/controlhandler.go +++ b/internal/server/handlers/controlhandler.go @@ -41,10 +41,12 @@ func NewControlHandler(user *user.User) *ControlHandler { return &h } +// Shutdown the handler. func (h *ControlHandler) Shutdown() { h.done.Shutdown() } +// Done channel of the handler. func (h *ControlHandler) Done() <-chan struct{} { return h.done.Done() } diff --git a/internal/server/handlers/serverhandler.go b/internal/server/handlers/serverhandler.go index 843eabc..5cf8041 100644 --- a/internal/server/handlers/serverhandler.go +++ b/internal/server/handlers/serverhandler.go @@ -72,10 +72,12 @@ func NewServerHandler(user *user.User, catLimiter, tailLimiter, globalServerWait return &h } +// Shutdown the handler. func (h *ServerHandler) Shutdown() { h.done.Shutdown() } +// Done channel of the handler. func (h *ServerHandler) Done() <-chan struct{} { return h.done.Done() } diff --git a/internal/server/scheduler.go b/internal/server/scheduler.go index 9d76a3b..a1e9e36 100644 --- a/internal/server/scheduler.go +++ b/internal/server/scheduler.go @@ -93,7 +93,7 @@ func (s *scheduler) runJobs(ctx context.Context) { defer cancel() logger.Info(fmt.Sprintf("Starting job %s", job.Name)) - status := client.Start(jobCtx, make(chan struct{})) + status := client.Start(jobCtx, make(chan string)) logMessage := fmt.Sprintf("Job exited with status %d", status) if status != 0 { -- cgit v1.2.3 From dccbee7dc355438d87baff45e054848e508b004d Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Tue, 8 Dec 2020 14:32:54 +0000 Subject: bump version --- internal/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/version/version.go b/internal/version/version.go index 750aaf2..b513b40 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -13,7 +13,7 @@ const ( // Version of DTail. Version string = "3.1.0" // Additional information for DTail - Additional string = "develop-II" + Additional string = "" // ProtocolCompat -ibility version. ProtocolCompat string = "3" ) -- cgit v1.2.3 From cf3308564c7ca46caba4a8a8649743f5cf0319bc Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 30 Jul 2021 08:51:05 +0300 Subject: initial color config support --- internal/color/color.go | 3 +-- internal/config/client.go | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/internal/color/color.go b/internal/color/color.go index 0736199..7309544 100644 --- a/internal/color/color.go +++ b/internal/color/color.go @@ -26,8 +26,7 @@ const ( Yellow Color = escape + "[36m" LightGray Color = escape + "[37m" - BgGray Color = escape + "[40m" - BgRed Color = escape + "[41m" + BgGray Color = escape + "[40m" BgRed Color = escape + "[41m" BgGreen Color = escape + "[42m" BgOrange Color = escape + "[43m" BgBlue Color = escape + "[44m" diff --git a/internal/config/client.go b/internal/config/client.go index 1515aae..3d8c45a 100644 --- a/internal/config/client.go +++ b/internal/config/client.go @@ -1,8 +1,25 @@ package config +// ClientColorConfig allows to override the default terminal color codes. +type ClientColorConfig struct { + OkBgColor Color +} + +/* + splitted := strings.Split(line, "|") + if splitted[2] == "100" { + splitted[2] = Paint(BgGreen, splitted[2]) + } else { + splitted[2] = Paint(BgRed, splitted[2]) + } + info := strings.Join(splitted[0:5], "|") + log := strings.Join(splitted[5:], "|") +*/ + // ClientConfig represents a DTail client configuration (empty as of now as there // are no available config options yet, but that may changes in the future). type ClientConfig struct { + TerminalColors ClientColorConfig `json:",omitempty"` } // Create a new default client configuration. -- cgit v1.2.3 From 805e84437cb2a1d1eefc7b7fed2dc6afa5421520 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 31 Jul 2021 17:53:03 +0300 Subject: Fix Docker tests - also add dcat example --- docker/Dockerfile | 2 +- docker/Makefile | 10 +++++++--- docker/serverlist.txt | 10 ++++++++++ docker/spindown.sh | 6 +++++- docker/spinup.sh | 4 +++- 5 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 docker/serverlist.txt diff --git a/docker/Dockerfile b/docker/Dockerfile index 8632832..779f75d 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -2,7 +2,7 @@ # The container can be used for developing and testing # Purposes -FROM fedora:33 +FROM fedora:34 RUN mkdir -p /etc/dserver /var/run/dserver/ /var/log/dserver ADD ./dtail.json /etc/dserver/dtail.json diff --git a/docker/Makefile b/docker/Makefile index 029adf6..eef32d7 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -1,10 +1,14 @@ -all: +all: build +testrun: build spinup dcat spindown +build: cp ../dserver . docker build . -t dserver:develop rm ./dserver -run: - docker run -p 2222:2222 dserver:develop spinup: ./spinup.sh 10 spindown: ./spindown.sh 10 +dcat: + ../dcat --servers serverlist.txt --files '/etc/passwd' --trustAllHosts +spinup1: + docker run -p 2222:2222 dserver:develop diff --git a/docker/serverlist.txt b/docker/serverlist.txt new file mode 100644 index 0000000..62a6ea6 --- /dev/null +++ b/docker/serverlist.txt @@ -0,0 +1,10 @@ +localhost:2223 +localhost:2224 +localhost:2225 +localhost:2226 +localhost:2227 +localhost:2228 +localhost:2229 +localhost:2230 +localhost:2231 +localhost:2232 diff --git a/docker/spindown.sh b/docker/spindown.sh index 73ed059..2202d22 100755 --- a/docker/spindown.sh +++ b/docker/spindown.sh @@ -5,5 +5,9 @@ declare -i BASE_PORT=2222 for (( i=0; i < $NUM_INSTANCES; i++ )); do port=$[ BASE_PORT + i + 1 ] - docker stop dserver-serv$i + name=dserver-serv$i + echo Stopping $name + docker stop $name + echo Removing $name + docker rm $name done diff --git a/docker/spinup.sh b/docker/spinup.sh index 3890ce6..399d781 100755 --- a/docker/spinup.sh +++ b/docker/spinup.sh @@ -5,5 +5,7 @@ declare -i BASE_PORT=2222 for (( i=0; i < $NUM_INSTANCES; i++ )); do port=$[ BASE_PORT + i + 1 ] - docker run -d --name dserver-serv$i --hostname serv$i -p $port:2222 dserver:develop + name=dserver-serv$i + echo Creating $name + docker run -d --name $name --hostname serv$i -p $port:2222 dserver:develop done -- cgit v1.2.3 From b526fcff5e490f926832d9aad43015eef67b0ad5 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 31 Jul 2021 18:20:03 +0300 Subject: more on configurable colors --- cmd/dcat/main.go | 5 ++-- cmd/dgrep/main.go | 5 ++-- cmd/dmap/main.go | 5 ++-- cmd/dserver/main.go | 8 ++--- cmd/dtail/main.go | 5 ++-- internal/color/color.go | 69 -------------------------------------------- internal/color/colorfy.go | 56 ----------------------------------- internal/config/client.go | 51 ++++++++++++++++++++++---------- internal/io/logger/logger.go | 10 +++---- internal/version/version.go | 3 +- 10 files changed, 57 insertions(+), 160 deletions(-) delete mode 100644 internal/color/color.go delete mode 100644 internal/color/colorfy.go diff --git a/cmd/dcat/main.go b/cmd/dcat/main.go index 238f97a..1aa7798 100644 --- a/cmd/dcat/main.go +++ b/cmd/dcat/main.go @@ -6,7 +6,6 @@ import ( "os" "github.com/mimecast/dtail/internal/clients" - "github.com/mimecast/dtail/internal/color" "github.com/mimecast/dtail/internal/config" "github.com/mimecast/dtail/internal/io/logger" "github.com/mimecast/dtail/internal/io/signal" @@ -42,7 +41,9 @@ func main() { flag.Parse() config.Read(cfgFile, sshPort) - color.Colored = !noColor + if noColor { + config.Client.TermColorsEnabled = false + } if displayVersion { version.PrintAndExit() diff --git a/cmd/dgrep/main.go b/cmd/dgrep/main.go index 4da1bb3..422bdd4 100644 --- a/cmd/dgrep/main.go +++ b/cmd/dgrep/main.go @@ -6,7 +6,6 @@ import ( "os" "github.com/mimecast/dtail/internal/clients" - "github.com/mimecast/dtail/internal/color" "github.com/mimecast/dtail/internal/config" "github.com/mimecast/dtail/internal/io/logger" "github.com/mimecast/dtail/internal/io/signal" @@ -46,7 +45,9 @@ func main() { flag.Parse() config.Read(cfgFile, sshPort) - color.Colored = !noColor + if noColor { + config.Client.TermColorsEnabled = false + } if displayVersion { version.PrintAndExit() diff --git a/cmd/dmap/main.go b/cmd/dmap/main.go index 1a05549..8a38069 100644 --- a/cmd/dmap/main.go +++ b/cmd/dmap/main.go @@ -6,7 +6,6 @@ import ( "os" "github.com/mimecast/dtail/internal/clients" - "github.com/mimecast/dtail/internal/color" "github.com/mimecast/dtail/internal/config" "github.com/mimecast/dtail/internal/io/logger" "github.com/mimecast/dtail/internal/io/signal" @@ -49,7 +48,9 @@ func main() { flag.Parse() config.Read(cfgFile, sshPort) - color.Colored = !noColor + if noColor { + config.Client.TermColorsEnabled = false + } if displayVersion { version.PrintAndExit() diff --git a/cmd/dserver/main.go b/cmd/dserver/main.go index 07f5270..5993481 100644 --- a/cmd/dserver/main.go +++ b/cmd/dserver/main.go @@ -12,7 +12,6 @@ import ( "syscall" "time" - "github.com/mimecast/dtail/internal/color" "github.com/mimecast/dtail/internal/config" "github.com/mimecast/dtail/internal/io/logger" "github.com/mimecast/dtail/internal/server" @@ -25,7 +24,7 @@ func main() { var cfgFile string var debugEnable bool var displayVersion bool - var noColor bool + var color bool var pprof int var shutdownAfter int var sshPort int @@ -35,16 +34,15 @@ func main() { flag.BoolVar(&debugEnable, "debug", false, "Activate debug messages") flag.BoolVar(&displayVersion, "version", false, "Display version") flag.BoolVar(&config.ServerRelaxedAuthEnable, "relaxedAuth", false, "Enable relaxced SSH auth mode (don't use in production!)") - flag.BoolVar(&noColor, "noColor", false, "Disable ANSII terminal colors") + flag.BoolVar(&color, "color", false, "Enable ANSII terminal colors") flag.IntVar(&pprof, "pprof", -1, "Start PProf server this port") flag.IntVar(&shutdownAfter, "shutdownAfter", 0, "Automatically shutdown after so many seconds") flag.IntVar(&sshPort, "port", 2222, "SSH server port") flag.StringVar(&cfgFile, "cfg", "", "Config file path") flag.Parse() - config.Read(cfgFile, sshPort) - color.Colored = !noColor + config.Client.TermColorsEnabled = color if displayVersion { version.PrintAndExit() diff --git a/cmd/dtail/main.go b/cmd/dtail/main.go index f2a039f..178ea52 100644 --- a/cmd/dtail/main.go +++ b/cmd/dtail/main.go @@ -11,7 +11,6 @@ import ( "time" "github.com/mimecast/dtail/internal/clients" - "github.com/mimecast/dtail/internal/color" "github.com/mimecast/dtail/internal/config" "github.com/mimecast/dtail/internal/io/logger" "github.com/mimecast/dtail/internal/io/signal" @@ -65,7 +64,9 @@ func main() { } config.Read(cfgFile, sshPort) - color.Colored = !noColor + if noColor { + config.Client.TermColorsEnabled = false + } if displayVersion { version.PrintAndExit() diff --git a/internal/color/color.go b/internal/color/color.go deleted file mode 100644 index 7309544..0000000 --- a/internal/color/color.go +++ /dev/null @@ -1,69 +0,0 @@ -// Package color is used to prettify console output via ANSII terminal colors. -package color - -import ( - "fmt" -) - -// Color name. -type Color string - -// Attribute of a color. -type Attribute string - -// The possible color variations. -const ( - escape = "\x1b" - reset = escape + "[0m" - seq string = "%s%s%s" - - Gray Color = escape + "[30m" - Red Color = escape + "[31m" - Green Color = escape + "[32m" - Orange Color = escape + "[33m" - Blue Color = escape + "[34m" - Magenta Color = escape + "[35m" - Yellow Color = escape + "[36m" - LightGray Color = escape + "[37m" - - BgGray Color = escape + "[40m" BgRed Color = escape + "[41m" - BgGreen Color = escape + "[42m" - BgOrange Color = escape + "[43m" - BgBlue Color = escape + "[44m" - BgMagenta Color = escape + "[45m" - BgYellow Color = escape + "[46m" - BgLightGray Color = escape + "[47m" - - Bold Attribute = escape + "[1m" - Italic Attribute = escape + "[3m" - Underline Attribute = escape + "[4m" - ReverseColor Attribute = escape + "[7m" - - resetBold = escape + "[22m" - resetItalic = escape + "[23m" - resetUnderline = escape + "[24m" - - Test Color = BgYellow - TestAttr Attribute = Bold -) - -// Colored DTail client output enabled. -var Colored bool - -// Paint a given string in a given color. -func Paint(c Color, s string) string { - return fmt.Sprintf(seq, c, s, reset) -} - -// Attr adds a given attribute to a given string, such as "bold" or "italic". -func Attr(c Attribute, s string) string { - switch c { - case Bold: - return fmt.Sprintf(seq, Bold, s, resetBold) - case Italic: - return fmt.Sprintf(seq, Italic, s, resetItalic) - case Underline: - return fmt.Sprintf(seq, Underline, s, resetUnderline) - } - panic("Unknown attribute") -} diff --git a/internal/color/colorfy.go b/internal/color/colorfy.go deleted file mode 100644 index a2beb7a..0000000 --- a/internal/color/colorfy.go +++ /dev/null @@ -1,56 +0,0 @@ -package color - -import ( - "fmt" - "strings" -) - -// Add some color to log lines received from remote servers. -func paintRemote(line string) string { - splitted := strings.Split(line, "|") - if splitted[2] == "100" { - splitted[2] = Paint(BgGreen, splitted[2]) - } else { - splitted[2] = Paint(BgRed, splitted[2]) - } - info := strings.Join(splitted[0:5], "|") - log := strings.Join(splitted[5:], "|") - - if strings.HasPrefix(log, "WARN") { - log = Paint(BgYellow, log) - } else if strings.HasPrefix(log, "ERROR") { - log = Paint(BgRed, log) - } else if strings.HasPrefix(log, "FATAL") { - log = Attr(Bold, Paint(BgRed, log)) - } else { - log = Paint(Blue, log) - } - - return fmt.Sprintf("%s|%s", info, log) -} - -// Add some color to stats generated by the client. -func paintClientStats(line string) string { - splitted := strings.Split(line, "|") - first := strings.Join(splitted[0:4], "|") - connected := Paint(BgBlue, splitted[4]) - last := strings.Join(splitted[5:], "|") - - return fmt.Sprintf("%s|%s|%s", first, connected, last) -} - -// Colorfy a given line based on the line's content. -func Colorfy(line string) string { - switch { - case strings.HasPrefix(line, "REMOTE"): - return paintRemote(line) - case strings.HasPrefix(line, "CLIENT") && strings.Contains(line, "|stats|"): - return paintClientStats(line) - case strings.Contains(line, "ERROR"): - return Paint(Magenta, line) - case strings.Contains(line, "WARN"): - return Paint(Magenta, line) - } - - return line -} diff --git a/internal/config/client.go b/internal/config/client.go index 3d8c45a..d6d106f 100644 --- a/internal/config/client.go +++ b/internal/config/client.go @@ -1,28 +1,47 @@ package config -// ClientColorConfig allows to override the default terminal color codes. -type ClientColorConfig struct { - OkBgColor Color -} +import "github.com/mimecast/dtail/internal/color" -/* - splitted := strings.Split(line, "|") - if splitted[2] == "100" { - splitted[2] = Paint(BgGreen, splitted[2]) - } else { - splitted[2] = Paint(BgRed, splitted[2]) - } - info := strings.Join(splitted[0:5], "|") - log := strings.Join(splitted[5:], "|") -*/ +// ClientColorConfig allows to override the default terminal color color. +type termColors struct { + RemoteTextFg color.Color + RemoteStatsOkBg color.Color + RemoteStatsWarnBg color.Color + RemoteTraceBg color.Color + RemoteDebugBg color.Color + RemoteWarnBg color.Color + RemoteErrorBg color.Color + RemoteFatalBg color.Color + RemoteFatalAttr color.Attribute + ClientStatsBg color.Color + ClientWarnFg color.Color + ClientErrorFg color.Color +} // ClientConfig represents a DTail client configuration (empty as of now as there // are no available config options yet, but that may changes in the future). type ClientConfig struct { - TerminalColors ClientColorConfig `json:",omitempty"` + TermColorsEnabled bool + TermColors termColors `json:",omitempty"` } // Create a new default client configuration. func newDefaultClientConfig() *ClientConfig { - return &ClientConfig{} + return &ClientConfig{ + TermColorsEnabled: true, + TermColors: termColors{ + RemoteTextFg: color.LightGray, + RemoteStatsOkBg: color.BgGreen, + RemoteStatsWarnBg: color.BgRed, + RemoteTraceBg: color.BgYellow, + RemoteDebugBg: color.BgYellow, + RemoteWarnBg: color.BgYellow, + RemoteErrorBg: color.BgRed, + RemoteFatalBg: color.BgRed, + RemoteFatalAttr: color.Bold, + ClientStatsBg: color.BgBlue, + ClientWarnFg: color.Purple, + ClientErrorFg: color.BgRed, + }, + } } diff --git a/internal/io/logger/logger.go b/internal/io/logger/logger.go index 4254eef..bef5293 100644 --- a/internal/io/logger/logger.go +++ b/internal/io/logger/logger.go @@ -12,7 +12,7 @@ import ( "syscall" "time" - "github.com/mimecast/dtail/internal/color" + "github.com/mimecast/dtail/internal/color/brush" "github.com/mimecast/dtail/internal/config" ) @@ -207,8 +207,8 @@ func write(what, severity, message string) { if Mode.logToStdout { line := fmt.Sprintf("%s|%s|%s|%s\n", what, hostname, severity, message) - if color.Colored { - line = color.Colorfy(line) + if config.Client.TermColorsEnabled { + line = brush.Colorfy(line) } stdoutBufCh <- line @@ -262,8 +262,8 @@ func Raw(message string) { } if Mode.logToStdout { - if color.Colored { - message = color.Colorfy(message) + if config.Client.TermColorsEnabled { + message = brush.Colorfy(message) } stdoutBufCh <- message } diff --git a/internal/version/version.go b/internal/version/version.go index c0f349c..7c206b4 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -5,6 +5,7 @@ import ( "os" "github.com/mimecast/dtail/internal/color" + "github.com/mimecast/dtail/internal/config" ) const ( @@ -25,7 +26,7 @@ func String() string { // PaintedString is a prettier string representation of the DTail version. func PaintedString() string { - if !color.Colored { + if !config.Client.TermColorsEnabled { return String() } name := color.Paint(color.Yellow, Name) -- cgit v1.2.3 From c427aecfa9a01ce63bb8a064c23b5a467de2eadc Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Mon, 9 Aug 2021 10:22:54 +0300 Subject: we have all basic ansi text color codes and attributes now. we can also convert a string to a corresponding code (e.g. from a config file). --- internal/color/color.go | 164 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 internal/color/color.go diff --git a/internal/color/color.go b/internal/color/color.go new file mode 100644 index 0000000..c6760d5 --- /dev/null +++ b/internal/color/color.go @@ -0,0 +1,164 @@ +// Package color contains all terminal color codes we know of. +package color + +import ( + "fmt" + "strings" +) + +// FgColor is the text foreground color. +type FgColor string + +// BgColor is the text background color. +type BgColor string + +// Attribute of text. +type Attribute string + +// The possible color variations. +const ( + escape = "\x1b" + seq string = "%s%s%s" + + FgBlack FgColor = escape + "[30m" + FgRed FgColor = escape + "[31m" + FgGreen FgColor = escape + "[32m" + FgYellow FgColor = escape + "[33m" + FgBlue FgColor = escape + "[34m" + FgMagenta FgColor = escape + "[35m" + FgCyan FgColor = escape + "[36m" + FgWhite FgColor = escape + "[37m" + FgDefault FgColor = escape + "[39m" + + BgBlack BgColor = escape + "[40m" + BgRed BgColor = escape + "[41m" + BgGreen BgColor = escape + "[42m" + BgYellow BgColor = escape + "[43m" + BgBlue BgColor = escape + "[44m" + BgMagenta BgColor = escape + "[45m" + BgCyan BgColor = escape + "[46m" + BgWhite BgColor = escape + "[47m" + BgDefault BgColor = escape + "[49m" + + AttReset Attribute = escape + "[0m" + AttBold Attribute = escape + "[1m" + AttDim Attribute = escape + "[2m" + AttItalic Attribute = escape + "[3m" + AttUnderline Attribute = escape + "[4m" + AttBlink Attribute = escape + "[5m" + AttSlowBlink Attribute = escape + "[5m" + AttRapidBlink Attribute = escape + "[6m" + AttReverse Attribute = escape + "[7m" + AttHidden Attribute = escape + "[8m" + + // Internal (manual) testing. + FgTest FgColor = FgBlue + BgTest BgColor = BgYellow + AttTest Attribute = AttBold +) + +// Colored DTail client output enabled. +var Colored bool + +// Paint paints a given text in a given foreground/background color combination. +func Paint(fg FgColor, bg FgColor, text string) string { + return fmt.Sprintf(seq, fg, bg, text, BgDefault, FgDefault) +} + +// PaintWithAttr paints a given text in a given foreground/background/attribute combination +func PaintWithAtt(fg FgColor, bg FgColor, att Attribute, text string) string { + return fmt.Sprintf(seq, fg, bg, att, text, AttReset, BgDefault, FgDefault) +} + +// PaintFg paints a given text in a given foreground color. +func PaintFg(fg FgColor, text string) string { + return fmt.Sprintf(seq, fg, text, FgDefault) +} + +// PaintBg paints a given text in a given background color. +func PaintBg(bg BgColor, text string) string { + return fmt.Sprintf(seq, bg, text, BgDefault) +} + +// PaintAtt adds a given attribute to a given text, such as "bold" or "italic". +func PaintAtt(att Attribute, text string) string { + return fmt.Sprintf(seq, att, text, AttReset) +} + +// ToFgColor converts a given string (e.g. from a config file) into a foreground color code. +func ToFgColor(s string) (FgColor, error) { + switch strings.ToLower(s) { + case "black": + return FgBlack, nil + case "red": + return FgRed, nil + case "green": + return FgGreen, nil + case "yellow": + return FgYellow, nil + case "blue": + return FgBlue, nil + case "magenta": + return FgMagenta, nil + case "cyan": + return FgCyan, nil + case "white": + return FgWhite, nil + case "default": + return FgDefault, nil + default: + return FgDefault, fmt.Errorf("unknown foreground text color '" + s + "'") + } +} + +// ToBgColor converts a given string (e.g. from a config file) into a background color code. +func ToBgColor(s string) (BgColor, error) { + switch strings.ToLower(s) { + case "black": + return BgBlack, nil + case "red": + return BgRed, nil + case "green": + return BgGreen, nil + case "yellow": + return BgYellow, nil + case "blue": + return BgBlue, nil + case "magenta": + return BgMagenta, nil + case "cyan": + return BgCyan, nil + case "white": + return BgWhite, nil + case "default": + return BgDefault, nil + default: + return BgDefault, fmt.Errorf("unknown background text color '" + s + "'") + } +} + +// ToAttribute converts a given string (e.g. from a config file) into a text attribute. +func ToAttColor(s string) (Attribute, error) { + switch strings.ToLower(s) { + case "bold": + return AttBold, nil + case "dim": + return AttDim, nil + case "italic": + return AttItalic, nil + case "underline": + return AttUnderline, nil + case "blink": + return AttBlink, nil + case "slowblink": + return AttSlowBlink, nil + case "rapidblink": + return AttRapidBlink, nil + case "reverse": + return AttReverse, nil + case "hidden": + return AttHidden, nil + default: + return AttReset, fmt.Errorf("unknown text attribute '" + s + "'") + } +} -- cgit v1.2.3 From 3901dff1d36de49c209aa017118bea12c35ba9c7 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Mon, 9 Aug 2021 10:33:57 +0300 Subject: change paint API --- internal/color/color.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/color/color.go b/internal/color/color.go index c6760d5..52a5752 100644 --- a/internal/color/color.go +++ b/internal/color/color.go @@ -61,27 +61,27 @@ const ( var Colored bool // Paint paints a given text in a given foreground/background color combination. -func Paint(fg FgColor, bg FgColor, text string) string { +func Paint(text string, fg FgColor, bg FgColor) string { return fmt.Sprintf(seq, fg, bg, text, BgDefault, FgDefault) } // PaintWithAttr paints a given text in a given foreground/background/attribute combination -func PaintWithAtt(fg FgColor, bg FgColor, att Attribute, text string) string { +func PaintWithAtt(text string, fg FgColor, bg FgColor, att Attribute) string { return fmt.Sprintf(seq, fg, bg, att, text, AttReset, BgDefault, FgDefault) } // PaintFg paints a given text in a given foreground color. -func PaintFg(fg FgColor, text string) string { +func PaintFg(text string, fg FgColor) string { return fmt.Sprintf(seq, fg, text, FgDefault) } // PaintBg paints a given text in a given background color. -func PaintBg(bg BgColor, text string) string { +func PaintBg(text string, bg BgColor) string { return fmt.Sprintf(seq, bg, text, BgDefault) } // PaintAtt adds a given attribute to a given text, such as "bold" or "italic". -func PaintAtt(att Attribute, text string) string { +func PaintAtt(text string, att Attribute) string { return fmt.Sprintf(seq, att, text, AttReset) } -- cgit v1.2.3 From de541a541857bddce6f7aa89c4e4525ebecc4d39 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Tue, 10 Aug 2021 11:23:07 +0300 Subject: add color unit test --- internal/color/color.go | 68 ++++++++++++++++++++------------------------ internal/color/color_test.go | 57 +++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 37 deletions(-) create mode 100644 internal/color/color_test.go diff --git a/internal/color/color.go b/internal/color/color.go index 52a5752..965675f 100644 --- a/internal/color/color.go +++ b/internal/color/color.go @@ -17,8 +17,7 @@ type Attribute string // The possible color variations. const ( - escape = "\x1b" - seq string = "%s%s%s" + escape = "\x1b" FgBlack FgColor = escape + "[30m" FgRed FgColor = escape + "[31m" @@ -40,49 +39,44 @@ const ( BgWhite BgColor = escape + "[47m" BgDefault BgColor = escape + "[49m" - AttReset Attribute = escape + "[0m" - AttBold Attribute = escape + "[1m" - AttDim Attribute = escape + "[2m" - AttItalic Attribute = escape + "[3m" - AttUnderline Attribute = escape + "[4m" - AttBlink Attribute = escape + "[5m" - AttSlowBlink Attribute = escape + "[5m" - AttRapidBlink Attribute = escape + "[6m" - AttReverse Attribute = escape + "[7m" - AttHidden Attribute = escape + "[8m" - - // Internal (manual) testing. - FgTest FgColor = FgBlue - BgTest BgColor = BgYellow - AttTest Attribute = AttBold + AttrReset Attribute = escape + "[0m" + AttrBold Attribute = escape + "[1m" + AttrDim Attribute = escape + "[2m" + AttrItalic Attribute = escape + "[3m" + AttrUnderline Attribute = escape + "[4m" + AttrBlink Attribute = escape + "[5m" + AttrSlowBlink Attribute = escape + "[5m" + AttrRapidBlink Attribute = escape + "[6m" + AttrReverse Attribute = escape + "[7m" + AttrHidden Attribute = escape + "[8m" ) // Colored DTail client output enabled. var Colored bool // Paint paints a given text in a given foreground/background color combination. -func Paint(text string, fg FgColor, bg FgColor) string { - return fmt.Sprintf(seq, fg, bg, text, BgDefault, FgDefault) +func Paint(text string, fg FgColor, bg BgColor) string { + return fmt.Sprintf("%s%s%s%s%s", fg, bg, text, BgDefault, FgDefault) } // PaintWithAttr paints a given text in a given foreground/background/attribute combination -func PaintWithAtt(text string, fg FgColor, bg FgColor, att Attribute) string { - return fmt.Sprintf(seq, fg, bg, att, text, AttReset, BgDefault, FgDefault) +func PaintWithAttr(text string, fg FgColor, bg BgColor, attr Attribute) string { + return fmt.Sprintf("%s%s%s%s%s%s%s", fg, bg, attr, text, AttrReset, BgDefault, FgDefault) } // PaintFg paints a given text in a given foreground color. func PaintFg(text string, fg FgColor) string { - return fmt.Sprintf(seq, fg, text, FgDefault) + return fmt.Sprintf("%s%s%s", fg, text, FgDefault) } // PaintBg paints a given text in a given background color. func PaintBg(text string, bg BgColor) string { - return fmt.Sprintf(seq, bg, text, BgDefault) + return fmt.Sprintf("%s%s%s", bg, text, BgDefault) } -// PaintAtt adds a given attribute to a given text, such as "bold" or "italic". -func PaintAtt(text string, att Attribute) string { - return fmt.Sprintf(seq, att, text, AttReset) +// PaintAttr adds a given attribute to a given text, such as "bold" or "italic". +func PaintAttr(text string, attr Attribute) string { + return fmt.Sprintf("%s%s%s", attr, text, AttrReset) } // ToFgColor converts a given string (e.g. from a config file) into a foreground color code. @@ -138,27 +132,27 @@ func ToBgColor(s string) (BgColor, error) { } // ToAttribute converts a given string (e.g. from a config file) into a text attribute. -func ToAttColor(s string) (Attribute, error) { +func ToAttribute(s string) (Attribute, error) { switch strings.ToLower(s) { case "bold": - return AttBold, nil + return AttrBold, nil case "dim": - return AttDim, nil + return AttrDim, nil case "italic": - return AttItalic, nil + return AttrItalic, nil case "underline": - return AttUnderline, nil + return AttrUnderline, nil case "blink": - return AttBlink, nil + return AttrBlink, nil case "slowblink": - return AttSlowBlink, nil + return AttrSlowBlink, nil case "rapidblink": - return AttRapidBlink, nil + return AttrRapidBlink, nil case "reverse": - return AttReverse, nil + return AttrReverse, nil case "hidden": - return AttHidden, nil + return AttrHidden, nil default: - return AttReset, fmt.Errorf("unknown text attribute '" + s + "'") + return AttrReset, fmt.Errorf("unknown text attribute '" + s + "'") } } diff --git a/internal/color/color_test.go b/internal/color/color_test.go new file mode 100644 index 0000000..0024b7f --- /dev/null +++ b/internal/color/color_test.go @@ -0,0 +1,57 @@ +package color + +import ( + "strings" + "testing" +) + +func TestColors(t *testing.T) { + colors := []string{ + "Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White", "Default", + } + + text := " Mimecast " + builder := strings.Builder{} + + for _, color := range colors { + fgColor, err := ToFgColor(color) + if err != nil { + t.Errorf("unable to paint foreground : %s\n%v", text, err) + } + builder.WriteString(PaintFg(text, fgColor)) + + bgColor, err := ToBgColor(color) + if err != nil { + t.Errorf("unable to paint background: %s\n%v", text, err) + } + builder.WriteString(PaintBg(text, bgColor)) + } + + for _, color := range colors { + fgColor, _ := ToFgColor(color) + for _, color := range colors { + bgColor, _ := ToBgColor(color) + builder.WriteString(Paint(text, fgColor, bgColor)) + } + } + + t.Log(builder.String()) +} +func TestAttributes(t *testing.T) { + attributes := []string{ + "Bold", "Dim", "Italic", "Underline", "Blink", "SlowBlink", "RapidBlink", "Reverse", "hidden", + } + + text := " Mimecast " + builder := strings.Builder{} + + for _, attribute := range attributes { + att, err := ToAttribute(attribute) + if err != nil { + t.Errorf("unable to paint attribute: %s\n%v", text, err) + } + builder.WriteString(PaintWithAttr(text, FgWhite, BgBlue, att)) + } + + t.Log(builder.String()) +} -- cgit v1.2.3 From 03fdeabe6b1e922d0ad064bdcc892b3ccf5ba551 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Tue, 10 Aug 2021 12:05:40 +0300 Subject: can compile with new color codes --- internal/color/color.go | 4 ++ internal/config/client.go | 108 ++++++++++++++++++++++++++++++++++---------- internal/version/version.go | 21 ++++++--- 3 files changed, 104 insertions(+), 29 deletions(-) diff --git a/internal/color/color.go b/internal/color/color.go index 965675f..f444294 100644 --- a/internal/color/color.go +++ b/internal/color/color.go @@ -39,6 +39,7 @@ const ( BgWhite BgColor = escape + "[47m" BgDefault BgColor = escape + "[49m" + AttrNone Attribute = "" AttrReset Attribute = escape + "[0m" AttrBold Attribute = escape + "[1m" AttrDim Attribute = escape + "[2m" @@ -61,6 +62,9 @@ func Paint(text string, fg FgColor, bg BgColor) string { // PaintWithAttr paints a given text in a given foreground/background/attribute combination func PaintWithAttr(text string, fg FgColor, bg BgColor, attr Attribute) string { + if attr == AttrNone { + return Paint(text, fg, bg) + } return fmt.Sprintf("%s%s%s%s%s%s%s", fg, bg, attr, text, AttrReset, BgDefault, FgDefault) } diff --git a/internal/config/client.go b/internal/config/client.go index d6d106f..84ad037 100644 --- a/internal/config/client.go +++ b/internal/config/client.go @@ -4,18 +4,49 @@ import "github.com/mimecast/dtail/internal/color" // ClientColorConfig allows to override the default terminal color color. type termColors struct { - RemoteTextFg color.Color - RemoteStatsOkBg color.Color - RemoteStatsWarnBg color.Color - RemoteTraceBg color.Color - RemoteDebugBg color.Color - RemoteWarnBg color.Color - RemoteErrorBg color.Color - RemoteFatalBg color.Color - RemoteFatalAttr color.Attribute - ClientStatsBg color.Color - ClientWarnFg color.Color - ClientErrorFg color.Color + ClientErrorAttr color.Attribute + ClientErrorBg color.BgColor + ClientErrorFg color.FgColor + + ClientStatsAttr color.Attribute + ClientStatsBg color.BgColor + ClientStatsFg color.FgColor + + ClientWarnAttr color.Attribute + ClientWarnBg color.BgColor + ClientWarnFg color.FgColor + + RemoteDebugAttr color.Attribute + RemoteDebugBg color.BgColor + RemoteDebugFg color.FgColor + + RemoteErrorAttr color.Attribute + RemoteErrorBg color.BgColor + RemoteErrorFg color.FgColor + + RemoteFatalAttr color.Attribute + RemoteFatalBg color.BgColor + RemoteFatalFg color.FgColor + + RemoteStatsOkAttr color.Attribute + RemoteStatsOkBg color.BgColor + RemoteStatsOkFg color.FgColor + + RemoteStatsWarnAttr color.Attribute + RemoteStatsWarnBg color.BgColor + RemoteStatsWarnFg color.FgColor + + RemoteTextAttr color.Attribute + RemoteTextBg color.BgColor + RemoteTextFg color.FgColor + + RemoteTraceAttr color.Attribute + RemoteTraceBg color.BgColor + RemoteTraceFg color.FgColor + + RemoteWarnAttr color.Attribute + RemoteWarnBg color.BgColor + RemoteWarnFg color.FgColor } // ClientConfig represents a DTail client configuration (empty as of now as there @@ -30,18 +61,49 @@ func newDefaultClientConfig() *ClientConfig { return &ClientConfig{ TermColorsEnabled: true, TermColors: termColors{ - RemoteTextFg: color.LightGray, + ClientErrorAttr: color.AttrBold, + ClientErrorBg: color.BgBlack, + ClientErrorFg: color.FgRed, + + ClientStatsAttr: color.AttrDim, + ClientStatsBg: color.BgBlue, + ClientStatsFg: color.FgWhite, + + ClientWarnAttr: color.AttrNone, + ClientWarnBg: color.BgBlack, + ClientWarnFg: color.FgMagenta, + + RemoteDebugAttr: color.AttrNone, + RemoteDebugBg: color.BgGreen, + RemoteDebugFg: color.FgWhite, + + RemoteErrorAttr: color.AttrBold, + RemoteErrorBg: color.BgRed, + RemoteErrorFg: color.FgWhite, + + RemoteFatalAttr: color.AttrBlink, + RemoteFatalBg: color.BgRed, + RemoteFatalFg: color.FgBlue, + + RemoteStatsOkAttr: color.AttrNone, RemoteStatsOkBg: color.BgGreen, - RemoteStatsWarnBg: color.BgRed, - RemoteTraceBg: color.BgYellow, - RemoteDebugBg: color.BgYellow, - RemoteWarnBg: color.BgYellow, - RemoteErrorBg: color.BgRed, - RemoteFatalBg: color.BgRed, - RemoteFatalAttr: color.Bold, - ClientStatsBg: color.BgBlue, - ClientWarnFg: color.Purple, - ClientErrorFg: color.BgRed, + RemoteStatsOkFg: color.FgWhite, + + RemoteStatsWarnAttr: color.AttrNone, + RemoteStatsWarnBg: color.BgRed, + RemoteStatsWarnFg: color.FgWhite, + + RemoteTextAttr: color.AttrNone, + RemoteTextBg: color.BgBlack, + RemoteTextFg: color.FgWhite, + + RemoteTraceAttr: color.AttrBold, + RemoteTraceBg: color.BgGreen, + RemoteTraceFg: color.FgWhite, + + RemoteWarnAttr: color.AttrBold, + RemoteWarnBg: color.BgYellow, + RemoteWarnFg: color.FgWhite, }, } } diff --git a/internal/version/version.go b/internal/version/version.go index 7c206b4..a513fdc 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -13,10 +13,10 @@ const ( Name string = "DTail" // Version of DTail. Version string = "3.2.0" - // Additional information for DTail - Additional string = "" // ProtocolCompat -ibility version. ProtocolCompat string = "3" + // Additional information for DTail + Additional string = "Have a lot of fun!" ) // String representation of the DTail version. @@ -29,11 +29,20 @@ func PaintedString() string { if !config.Client.TermColorsEnabled { return String() } - name := color.Paint(color.Yellow, Name) - version := color.Paint(color.Blue, Version) - descr := color.Paint(color.Green, Additional) - return fmt.Sprintf("%s %v Protocol %s %s", name, version, ProtocolCompat, descr) + name := color.PaintWithAttr(Name, + color.FgYellow, color.BgBlue, color.AttrBold) + + version := color.PaintWithAttr(fmt.Sprintf(" %s ", Version), + color.FgBlue, color.BgYellow, color.AttrBold) + + protocol := color.Paint(fmt.Sprintf(" Protocol %s ", ProtocolCompat), + color.FgBlack, color.BgGreen) + + additional := color.PaintWithAttr(fmt.Sprintf(" %s ", Additional), + color.FgWhite, color.BgMagenta, color.AttrBlink) + + return fmt.Sprintf("%s%v%s%s", name, version, protocol, additional) } // PrintAndExit prints the program version and exists. -- cgit v1.2.3 From 5fdaa4ef60c134f4cb6cb64159aad59a55e0dd11 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Wed, 11 Aug 2021 09:32:13 +0300 Subject: add colorTable option --- cmd/dtail/main.go | 8 +++++++- internal/color/color.go | 4 ++++ internal/color/color_test.go | 23 +++++++++-------------- internal/color/table.go | 41 +++++++++++++++++++++++++++++++++++++++++ internal/config/client.go | 6 +++--- internal/version/version.go | 2 +- 6 files changed, 65 insertions(+), 19 deletions(-) create mode 100644 internal/color/table.go diff --git a/cmd/dtail/main.go b/cmd/dtail/main.go index 178ea52..869a536 100644 --- a/cmd/dtail/main.go +++ b/cmd/dtail/main.go @@ -11,6 +11,7 @@ import ( "time" "github.com/mimecast/dtail/internal/clients" + "github.com/mimecast/dtail/internal/color" "github.com/mimecast/dtail/internal/config" "github.com/mimecast/dtail/internal/io/logger" "github.com/mimecast/dtail/internal/io/signal" @@ -25,6 +26,7 @@ func main() { var cfgFile string var checkHealth bool var debugEnable bool + var displayColorTable bool var displayVersion bool var grep string var noColor bool @@ -35,13 +37,14 @@ func main() { userName := user.Name() + flag.BoolVar(&args.Quiet, "quiet", false, "Quiet output mode") flag.BoolVar(&args.RegexInvert, "invert", false, "Invert regex") flag.BoolVar(&args.TrustAllHosts, "trustAllHosts", false, "Auto trust all unknown host keys") flag.BoolVar(&checkHealth, "checkHealth", false, "Only check for server health") flag.BoolVar(&debugEnable, "debug", false, "Activate debug messages") + flag.BoolVar(&displayColorTable, "colorTable", false, "Show color table") flag.BoolVar(&displayVersion, "version", false, "Display version") flag.BoolVar(&noColor, "noColor", false, "Disable ANSII terminal colors") - flag.BoolVar(&args.Quiet, "quiet", false, "Quiet output mode") flag.IntVar(&args.ConnectionsPerCPU, "cpc", 10, "How many connections established per CPU core concurrently") flag.IntVar(&args.Timeout, "timeout", 0, "Max time dtail server will collect data until disconnection") flag.IntVar(&pprof, "pprof", -1, "Start PProf server this port") @@ -71,6 +74,9 @@ func main() { if displayVersion { version.PrintAndExit() } + if displayColorTable { + color.TablePrintAndExit() + } ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/internal/color/color.go b/internal/color/color.go index f444294..a2490be 100644 --- a/internal/color/color.go +++ b/internal/color/color.go @@ -156,6 +156,10 @@ func ToAttribute(s string) (Attribute, error) { return AttrReverse, nil case "hidden": return AttrHidden, nil + case "none": + fallthrough + case "": + return AttrNone, nil default: return AttrReset, fmt.Errorf("unknown text attribute '" + s + "'") } diff --git a/internal/color/color_test.go b/internal/color/color_test.go index 0024b7f..16b2f90 100644 --- a/internal/color/color_test.go +++ b/internal/color/color_test.go @@ -6,14 +6,10 @@ import ( ) func TestColors(t *testing.T) { - colors := []string{ - "Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White", "Default", - } - text := " Mimecast " builder := strings.Builder{} - for _, color := range colors { + for _, color := range ColorNames { fgColor, err := ToFgColor(color) if err != nil { t.Errorf("unable to paint foreground : %s\n%v", text, err) @@ -27,10 +23,13 @@ func TestColors(t *testing.T) { builder.WriteString(PaintBg(text, bgColor)) } - for _, color := range colors { - fgColor, _ := ToFgColor(color) - for _, color := range colors { - bgColor, _ := ToBgColor(color) + for _, fg := range ColorNames { + fgColor, _ := ToFgColor(fg) + for _, bg := range ColorNames { + if fg == bg { + continue + } + bgColor, _ := ToBgColor(bg) builder.WriteString(Paint(text, fgColor, bgColor)) } } @@ -38,14 +37,10 @@ func TestColors(t *testing.T) { t.Log(builder.String()) } func TestAttributes(t *testing.T) { - attributes := []string{ - "Bold", "Dim", "Italic", "Underline", "Blink", "SlowBlink", "RapidBlink", "Reverse", "hidden", - } - text := " Mimecast " builder := strings.Builder{} - for _, attribute := range attributes { + for _, attribute := range AttributeNames { att, err := ToAttribute(attribute) if err != nil { t.Errorf("unable to paint attribute: %s\n%v", text, err) diff --git a/internal/color/table.go b/internal/color/table.go new file mode 100644 index 0000000..8e40a78 --- /dev/null +++ b/internal/color/table.go @@ -0,0 +1,41 @@ +package color + +import ( + "fmt" + "os" +) + +var ColorNames = []string{ + "Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White", "Default", +} + +var AttributeNames = []string{ + "Bold", "Dim", "Italic", "Underline", "Blink", "SlowBlink", "RapidBlink", "Reverse", "Hidden", "None", +} + +func TablePrintAndExit() { + for _, attr := range AttributeNames { + if attr == "Hidden" || attr == "SlowBlink" { + continue + } + printColorTable(attr) + } + os.Exit(0) +} + +func printColorTable(attr string) { + for _, fg := range ColorNames { + fgColor, _ := ToFgColor(fg) + for _, bg := range ColorNames { + if fg == bg { + continue + } + bgColor, _ := ToBgColor(bg) + attribute, _ := ToAttribute(attr) + + text := fmt.Sprintf(" Foreground:%10s | Background:%10s | Attribute:%10s ", fg, bg, attr) + fmt.Print(PaintWithAttr(text, fgColor, bgColor, attribute)) + fmt.Print("\n") + } + } +} diff --git a/internal/config/client.go b/internal/config/client.go index 84ad037..5386576 100644 --- a/internal/config/client.go +++ b/internal/config/client.go @@ -75,7 +75,7 @@ func newDefaultClientConfig() *ClientConfig { RemoteDebugAttr: color.AttrNone, RemoteDebugBg: color.BgGreen, - RemoteDebugFg: color.FgWhite, + RemoteDebugFg: color.FgBlack, RemoteErrorAttr: color.AttrBold, RemoteErrorBg: color.BgRed, @@ -83,11 +83,11 @@ func newDefaultClientConfig() *ClientConfig { RemoteFatalAttr: color.AttrBlink, RemoteFatalBg: color.BgRed, - RemoteFatalFg: color.FgBlue, + RemoteFatalFg: color.FgWhite, RemoteStatsOkAttr: color.AttrNone, RemoteStatsOkBg: color.BgGreen, - RemoteStatsOkFg: