frog

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2019 License: MIT Imports: 9 Imported by: 7

README

frog

Overview

Frog is a package for logging output.

When connected to a terminal, Frog allows lines to be fixed to the bottom of the output and updated quickly and efficiently. This allows for display of data that would be surperfluous in a log file, but is really nice to have when watching the output in a terminal.

Frog uses ANSI/VT-100 commands to change colors and move the cursor. Most terminals support these commands, although Windows is a special case. Windows consoles (cmd, powershell) only support ANSI in the more recent Windows 10 builds. Older versions of Windows require a third-party terminal like ConEmu/Cmdr or mintty to display Frog's colors and fixed lines properly.

animated gif of frog in action

Features

  • Multiple logging levels
  • Fixing one or more lines in place for progress bars and real-time status displays (via ANSI commands)
  • Colorized output (via ANSI commands)
  • Autodetection of connected terminal, and disabling of ANSI-based output as needed.
  • Loggers target the io.Writer interface, allowing your logs to be easily sent to files, buffers, etc.
  • Customizable line style, currently supporting a simple plain text format, as well as JSON
    • Alternatively, you can write your own Printer that can style each line however you like
  • Loggers can easily be written to target other loggers (see TeeLogger)

Usage

The quickest way to get started is to create one of the default Loggers via a call to New:

  log := frog.New(frog.Auto)
  defer log.Close()

  log.Infof("My first boring log line")
  log.Warningf("Also boring")

  status := frog.AddFixedLine(log)
  for i := 0; i <= 100; i++ {
    status.Transientf(" + %d%% complete", n)
    time.Sleep(time.Duration(10) * time.Millisecond)
  }
  status.Infof("Still boring!", n)

frog.Auto will use a Buffered Logger, but will only use ANSI if there's a detected terminal, and only displays color if ANSI is supported and if there's no NO_COLOR environment variable.

Another option is frog.JSON, which uses an Unbuffered Logger that formats each log line as a single JSON object. Switching the previous code example is as simple as changing the first line:

  log := frog.New(frog.JSON)
  ⋮

Notice that when you run this second example, all the Transient lines are not output. Transient lines are by default only output when sent to a Logger responsible for a fixed line.

Also notice that when we want to create a fixed line, we make a call on the frog package, and not directly to our Logger. Logger is an interface, and most implementations of that interface will probably not care about fixed lines, so it was decided not to make it a mandatory part of the Logger interface. Instead, any Logger that wants to support fixed liens will need to implement not only the Logger interface, but also the FixedLineAdder interface, which is what AddFixedLine looks for on the passed in Logger.

Here's a complete list of Frog's log levels, and their intended uses:

level description
Transient Data that is safe to ignore (like progress bars and estimated time remaining).
Verbose Data for debugging (disabled most of the time).
Info Normal log lines (usually enabled).
Warning Unusual events.
Error Something went wrong.
Fatal Display this text then halt the entire app.

TODO

  • Write to two Loggers simultaneously
  • JSON Printer
  • rework how fixed lines are released
  • hide cursor while it moves around during fixed line redraws
  • Structured logging
  • Only re-draw the parts of fixed lines that have changed

Documentation

Index

Constants

This section is empty.

Variables

View Source
var IsNoColorSet = false

Functions

func RemoveFixedLine added in v0.3.0

func RemoveFixedLine(log Logger)

Types

type Buffered

type Buffered struct {
	// contains filtered or unexported fields
}

func NewBuffered

func NewBuffered(cfg Config, prn Printer) *Buffered

func (*Buffered) AddFixedLine

func (l *Buffered) AddFixedLine() Logger

AddFixedLine creates a Logger that, when connected to a terminal, draws over itself. Thread safe.

func (*Buffered) Close

func (l *Buffered) Close()

Close should be called before the app exits, to ensure any buffered output is flushed. Thread safe.

func (*Buffered) Errorf

func (l *Buffered) Errorf(format string, a ...interface{}) Logger

func (*Buffered) Fatalf

func (l *Buffered) Fatalf(format string, a ...interface{})

func (*Buffered) Infof

func (l *Buffered) Infof(format string, a ...interface{}) Logger

func (*Buffered) Logf added in v0.2.0

func (l *Buffered) Logf(level Level, format string, a ...interface{}) Logger

func (*Buffered) SetMinLevel

func (l *Buffered) SetMinLevel(level Level) Logger

func (*Buffered) Transientf added in v0.2.0

func (l *Buffered) Transientf(format string, a ...interface{}) Logger

func (*Buffered) Verbosef

func (l *Buffered) Verbosef(format string, a ...interface{}) Logger

func (*Buffered) Warningf

func (l *Buffered) Warningf(format string, a ...interface{}) Logger

type ChildLogger added in v0.2.0

type ChildLogger interface {
	// Parent returns the parent Logger, or nil if it has no parent.
	Parent() Logger
}

ChildLogger is the interface for loggers that feed back to a parent.

type Config

type Config struct {
	Writer   io.Writer
	UseAnsi  bool
	UseColor bool
}

type FixedLine

type FixedLine struct {
	// contains filtered or unexported fields
}

FixedLine is a Logger that attempts to overwrite the same line in the terminal, allowing progress bars and other simple UI for the human to consume.

If the Printer's CanUseAnsi is false, then it simply redirects to the normal behavior of the parent Buffered Logger.

If the Printer's CanUseAnsi is true, then the Transient level is always printed, regardless of the MinLevel. This allows progress bars that do not pollute logs with garbage when not connected to a terminal.

func (*FixedLine) Close

func (l *FixedLine) Close()

func (*FixedLine) Errorf

func (l *FixedLine) Errorf(format string, a ...interface{}) Logger

func (*FixedLine) Fatalf

func (l *FixedLine) Fatalf(format string, a ...interface{})

func (*FixedLine) Infof

func (l *FixedLine) Infof(format string, a ...interface{}) Logger

func (*FixedLine) Logf added in v0.2.0

func (l *FixedLine) Logf(level Level, format string, a ...interface{}) Logger

func (*FixedLine) Parent added in v0.2.0

func (l *FixedLine) Parent() Logger

func (*FixedLine) RemoveFixedLine added in v0.3.0

func (l *FixedLine) RemoveFixedLine()

func (*FixedLine) SetMinLevel

func (l *FixedLine) SetMinLevel(level Level) Logger

func (*FixedLine) Transientf added in v0.2.0

func (l *FixedLine) Transientf(format string, a ...interface{}) Logger

func (*FixedLine) Verbosef

func (l *FixedLine) Verbosef(format string, a ...interface{}) Logger

func (*FixedLine) Warningf

func (l *FixedLine) Warningf(format string, a ...interface{}) Logger

type FixedLineAdder added in v0.3.0

type FixedLineAdder interface {
	AddFixedLine() Logger
}

FixedLineAdder is the interface for loggers that support fixing a line in place, for progress bars or other transient status messages.

type FixedLineRemover added in v0.3.0

type FixedLineRemover interface {
	RemoveFixedLine()
}

FixedLineRemover is the interface that a fixed line logger must implement in order for the fixed line to be removed before app end.

type JSONPrinter added in v0.2.1

type JSONPrinter struct {
	TimeOverride time.Time
}

func (*JSONPrinter) Render added in v0.2.1

func (p *JSONPrinter) Render(useAnsi bool, useColor bool, level Level, format string, a ...interface{}) string

type Level

type Level byte
const (
	Transient Level = iota // strictly unimportant, ie progress bars, real-time byte counts, estimated time remaining, etc
	Verbose                // debugging info
	Info                   // normal message
	Warning                // something unusual happened
	Error                  // something bad happened
	Fatal                  // stop everything right now

)

func (Level) String added in v0.2.1

func (l Level) String() string

type Logger

type Logger interface {
	// Close ensures any buffers are flushed and any resources released.
	// It is safe to call Close more than once (but consecutive calls do nothing).
	Close()

	// SetMinLevel sets the lowest Level that will be logged.
	SetMinLevel(level Level) Logger

	// Logf is how log lines are added.
	Logf(level Level, format string, a ...interface{}) Logger

	// Transientf et al are just shortcuts for calling Logf with specific levels
	// Note that Fatalf doesn't return itself like the others do because it isn't expected to return at all.
	Transientf(format string, a ...interface{}) Logger
	Verbosef(format string, a ...interface{}) Logger
	Infof(format string, a ...interface{}) Logger
	Warningf(format string, a ...interface{}) Logger
	Errorf(format string, a ...interface{}) Logger
	Fatalf(format string, a ...interface{})
}

func AddFixedLine added in v0.2.0

func AddFixedLine(log Logger) Logger

AddFixedLine adds a new logger on a fixed line, if supported. Else, returns passed in Logger.

func New

func New(t NewLogger) Logger

New creates a Buffered logger that writes to os.Stdout, and autodetects any attached Terminal on stdout to decide if ANSI should be used. The caller is responsible for calling Close() before the process ends.

func Parent added in v0.2.0

func Parent(log Logger) Logger

func ParentOrSelf added in v0.2.0

func ParentOrSelf(log Logger) Logger

type Msg

type Msg struct {
	Type  MsgType
	Line  int32
	Level Level
	Msg   string
}

type MsgType

type MsgType byte
const (
	MsgPrint      MsgType = iota // string to print
	MsgFatal                     // stop processor without closing channel
	MsgAddLine                   // add a fixed line
	MsgRemoveLine                // remove a fixed line
)

type NewLogger added in v0.2.0

type NewLogger byte
const (
	Auto NewLogger = iota
	Basic
	JSON
)

type Printer

type Printer interface {
	Render(useAnsi bool, useColor bool, level Level, format string, a ...interface{}) string
}

type TeeLogger added in v0.2.0

type TeeLogger struct {
	Primary   Logger
	Secondary Logger
}

TeeLogger directs all traffic to both a primary and secondary logger

func (*TeeLogger) AddFixedLine added in v0.2.0

func (l *TeeLogger) AddFixedLine() Logger

func (*TeeLogger) Close added in v0.2.0

func (l *TeeLogger) Close()

func (*TeeLogger) Errorf added in v0.2.0

func (l *TeeLogger) Errorf(format string, a ...interface{}) Logger

func (*TeeLogger) Fatalf added in v0.2.0

func (l *TeeLogger) Fatalf(format string, a ...interface{})

func (*TeeLogger) Infof added in v0.2.0

func (l *TeeLogger) Infof(format string, a ...interface{}) Logger

func (*TeeLogger) Logf added in v0.2.0

func (l *TeeLogger) Logf(level Level, format string, a ...interface{}) Logger

func (*TeeLogger) RemoveFixedLine added in v0.3.0

func (l *TeeLogger) RemoveFixedLine()

func (*TeeLogger) SetMinLevel added in v0.2.0

func (l *TeeLogger) SetMinLevel(level Level) Logger

func (*TeeLogger) Transientf added in v0.2.0

func (l *TeeLogger) Transientf(format string, a ...interface{}) Logger

func (*TeeLogger) Verbosef added in v0.2.0

func (l *TeeLogger) Verbosef(format string, a ...interface{}) Logger

func (*TeeLogger) Warningf added in v0.2.0

func (l *TeeLogger) Warningf(format string, a ...interface{}) Logger

type TextPrinter added in v0.2.1

type TextPrinter struct {
	PrintTime  bool
	PrintLevel bool
}

func (*TextPrinter) Render added in v0.2.1

func (p *TextPrinter) Render(useAnsi bool, useColor bool, level Level, format string, a ...interface{}) string

type Unbuffered added in v0.2.0

type Unbuffered struct {
	// contains filtered or unexported fields
}

func NewUnbuffered added in v0.2.0

func NewUnbuffered(w io.Writer, prn Printer) *Unbuffered

func (*Unbuffered) Close added in v0.2.0

func (l *Unbuffered) Close()

func (*Unbuffered) Errorf added in v0.2.0

func (l *Unbuffered) Errorf(format string, a ...interface{}) Logger

func (*Unbuffered) Fatalf added in v0.2.0

func (l *Unbuffered) Fatalf(format string, a ...interface{})

func (*Unbuffered) Infof added in v0.2.0

func (l *Unbuffered) Infof(format string, a ...interface{}) Logger

func (*Unbuffered) Logf added in v0.2.0

func (l *Unbuffered) Logf(level Level, format string, a ...interface{}) Logger

func (*Unbuffered) SetMinLevel added in v0.2.0

func (l *Unbuffered) SetMinLevel(level Level) Logger

func (*Unbuffered) Transientf added in v0.2.0

func (l *Unbuffered) Transientf(format string, a ...interface{}) Logger

func (*Unbuffered) Verbosef added in v0.2.0

func (l *Unbuffered) Verbosef(format string, a ...interface{}) Logger

func (*Unbuffered) Warningf added in v0.2.0

func (l *Unbuffered) Warningf(format string, a ...interface{}) Logger

Directories

Path Synopsis
cmd
example command
example2 command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL