-
Notifications
You must be signed in to change notification settings - Fork 558
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
services/serve: add prefixes to verbose logs (#129)
* services/serve: add prefixes to verbose logs * added new pkg/lineprefixer. * added new pkg/prefixgen. * added options builder to pkg/cmdrunner/step. * cosmetics. * fix tests & add missing file * add STARPORT prefix to native logs * add buildLog log type. * reorganize verbose logs. * fix linter * fix verbose logs
- Loading branch information
Showing
9 changed files
with
505 additions
and
118 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// Package lineprefixer is a helpers to add prefixes to new lines. | ||
package lineprefixer | ||
|
||
import ( | ||
"bytes" | ||
"io" | ||
) | ||
|
||
// Writer is a prefixed line writer. | ||
type Writer struct { | ||
prefix []byte | ||
w io.Writer | ||
shouldPrefix bool | ||
} | ||
|
||
// NewWriter returns a new Writer that adds prefixes to each line | ||
// written. It then writes prefixed data stream into w. | ||
func NewWriter(w io.Writer, prefix string) *Writer { | ||
return &Writer{ | ||
w: w, | ||
prefix: []byte(prefix), | ||
shouldPrefix: true, | ||
} | ||
} | ||
|
||
// Write implements io.Writer. | ||
func (p *Writer) Write(b []byte) (n int, err error) { | ||
var ( | ||
blen = len(b) | ||
lastChar = b[blen-1] | ||
newLine = byte('\n') | ||
snewLine = []byte{newLine} | ||
replaceCount = bytes.Count(b, snewLine) | ||
) | ||
if lastChar == newLine { | ||
replaceCount-- | ||
} | ||
b = bytes.Replace(b, snewLine, append(snewLine, p.prefix...), replaceCount) | ||
if p.shouldPrefix { | ||
b = append(p.prefix, b...) | ||
} | ||
p.shouldPrefix = lastChar == newLine | ||
if _, err := p.w.Write(b); err != nil { | ||
return 0, err | ||
} | ||
return blen, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package lineprefixer | ||
|
||
import ( | ||
"bytes" | ||
"io" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestWriter(t *testing.T) { | ||
logs := `hello, | ||
this | ||
is | ||
Starport!` | ||
buf := bytes.Buffer{} | ||
w := NewWriter(&buf, "[TENDERMINT] ") | ||
_, err := io.Copy(w, strings.NewReader(logs)) | ||
require.NoError(t, err) | ||
require.Equal(t, `[TENDERMINT] hello, | ||
[TENDERMINT] this | ||
[TENDERMINT] is | ||
[TENDERMINT] Starport!`, | ||
buf.String(), | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// Package prefixgen is a prefix generation helper for log messages | ||
// and any other kind. | ||
package prefixgen | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/gookit/color" | ||
) | ||
|
||
// Prefixer generates prefixes. | ||
type Prefixer struct { | ||
format string | ||
color uint8 | ||
left, right string | ||
convertUppercase bool | ||
} | ||
|
||
// Option configures Prefixer. | ||
type Option func(p *Prefixer) | ||
|
||
// Color sets color to the prefix. | ||
func Color(color uint8) Option { | ||
return func(p *Prefixer) { | ||
p.color = color | ||
} | ||
} | ||
|
||
// SquareBrackets adds square brackets to the prefix. | ||
func SquareBrackets() Option { | ||
return func(p *Prefixer) { | ||
p.left = "[" | ||
p.right = "]" | ||
} | ||
} | ||
|
||
// SpaceRight adds rights space to the prefix. | ||
func SpaceRight() Option { | ||
return func(p *Prefixer) { | ||
p.right += " " | ||
} | ||
} | ||
|
||
// Uppercase formats the prefix to uppercase. | ||
func Uppercase() Option { | ||
return func(p *Prefixer) { | ||
p.convertUppercase = true | ||
} | ||
} | ||
|
||
// Common holds some common prefix options and extends those | ||
// options by given options. | ||
func Common(options ...Option) []Option { | ||
return append([]Option{ | ||
SquareBrackets(), | ||
SpaceRight(), | ||
Uppercase(), | ||
}, options...) | ||
} | ||
|
||
// New creates a new Prefixer with format and options. | ||
// Format is an fmt.Sprintf() like format to dynamically create prefix texts | ||
// as needed. | ||
func New(format string, options ...Option) *Prefixer { | ||
p := &Prefixer{ | ||
format: format, | ||
} | ||
for _, o := range options { | ||
o(p) | ||
} | ||
return p | ||
} | ||
|
||
// Gen generates a new prefix by applying s to format given during New(). | ||
func (p *Prefixer) Gen(s ...interface{}) string { | ||
format := p.format | ||
format = p.left + format | ||
format = format + p.right | ||
prefix := fmt.Sprintf(format, s...) | ||
if p.convertUppercase { | ||
prefix = strings.ToUpper(prefix) | ||
} | ||
if p.color != 0 { | ||
return color.C256(p.color).Sprint(prefix) | ||
} | ||
return prefix | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package prefixgen | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestGen(t *testing.T) { | ||
cases := []struct { | ||
expected string | ||
given string | ||
}{ | ||
{"[TENDERMINT] ", New("Tendermint", Common()...).Gen()}, | ||
{"Tendermint", New("Tendermint").Gen()}, | ||
{"appd", New("%sd").Gen("app")}, | ||
} | ||
for _, tt := range cases { | ||
t.Run(tt.expected, func(t *testing.T) { | ||
require.Equal(t, tt.expected, tt.given) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package starportserve | ||
|
||
import ( | ||
"io" | ||
"os" | ||
"strings" | ||
|
||
"github.com/tendermint/starport/starport/pkg/cmdrunner/step" | ||
"github.com/tendermint/starport/starport/pkg/lineprefixer" | ||
"github.com/tendermint/starport/starport/pkg/prefixgen" | ||
) | ||
|
||
// prefixes holds prefix configuration for logs messages. | ||
var prefixes = map[logType]struct { | ||
Name string | ||
Color uint8 | ||
}{ | ||
logStarport: {"starport", 202}, | ||
logBuild: {"build", 203}, | ||
logAppd: {"%sd", 204}, | ||
logAppcli: {"%scli", 205}, | ||
} | ||
|
||
// logType represents the different types of logs. | ||
type logType int | ||
|
||
const ( | ||
logStarport logType = iota | ||
logBuild | ||
logAppd | ||
logAppcli | ||
) | ||
|
||
// std returns the cmdrunner steps to configure stdout and stderr to output logs by logType. | ||
func (s *starportServe) stdSteps(logType logType) []step.Option { | ||
std := s.stdLog(logType) | ||
return []step.Option{ | ||
step.Stdout(std.out), | ||
step.Stderr(std.err), | ||
} | ||
} | ||
|
||
type std struct { | ||
out, err io.Writer | ||
} | ||
|
||
// std returns the stdout and stderr to output logs by logType. | ||
func (s *starportServe) stdLog(logType logType) std { | ||
prefixed := func(w io.Writer) *lineprefixer.Writer { | ||
var ( | ||
prefix = prefixes[logType] | ||
prefixStr string | ||
options = prefixgen.Common(prefixgen.Color(prefix.Color)) | ||
gen = prefixgen.New(prefix.Name, options...) | ||
) | ||
if strings.Count(prefix.Name, "%s") > 0 { | ||
prefixStr = gen.Gen(s.app.Name) | ||
} else { | ||
prefixStr = gen.Gen() | ||
} | ||
return lineprefixer.NewWriter(w, prefixStr) | ||
} | ||
var ( | ||
stdout io.Writer = prefixed(s.stdout) | ||
stderr io.Writer = prefixed(s.stderr) | ||
) | ||
if logType == logStarport && !s.verbose { | ||
stdout = os.Stdout | ||
stderr = os.Stderr | ||
} | ||
return std{ | ||
out: stdout, | ||
err: stderr, | ||
} | ||
} |
Oops, something went wrong.