Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Log marker #24

Merged
merged 12 commits into from
Oct 26, 2019
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
go.sum
image_generator/typescript
104 changes: 76 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,54 +44,54 @@ Marker has very simple and extensible way to get your strings colorful and brill

#### MatchAll
```go
aristotleQuote := "The more you know, the more you realize you don't know."
emphasized := marker.Mark(aristotleQuote, marker.MatchAll("know"), color.New(color.FgRed))
fmt.Println(emphasized)
aristotleQuote := "The more you know, the more you realize you don't know."
emphasized := marker.Mark(aristotleQuote, marker.MatchAll("know"), color.New(color.FgRed))
fmt.Println(emphasized)
```
<img src="assets/png/matchall.png">

#### MatchN
```go
boringLog := "[INFO] Nobody wants to read pale [INFO] tags."
brilliantLog := marker.Mark(boringLog, marker.MatchN("[INFO]", 1), color.New(color.FgBlue))
fmt.Println(brilliantLog)
boringLog := "[INFO] Nobody wants to read pale [INFO] tags."
brilliantLog := marker.Mark(boringLog, marker.MatchN("[INFO]", 1), color.New(color.FgBlue))
fmt.Println(brilliantLog)
```
<img src="assets/png/matchn.png">

#### MatchRegexp

```go
rhyme := "I scream, you all scream, we all scream for ice cream."
r, _ := regexp.Compile("([a-z]?cream)")
careAboutCream := marker.Mark(rhyme, marker.MatchRegexp(r), color.New(color.FgYellow))
fmt.Println(careAboutCream)
rhyme := "I scream, you all scream, we all scream for ice cream."
r, _ := regexp.Compile("([a-z]?cream)")
careAboutCream := marker.Mark(rhyme, marker.MatchRegexp(r), color.New(color.FgYellow))
fmt.Println(careAboutCream)
```
<img src="assets/png/matchregex.png">

#### MatchSurrounded

```go
sentence := "I pull out things surrounded by abcWHOA COLORSdef"
markedSurrounded := marker.Mark(sentence, marker.MatchSurrounded("abc", "def"), magentaFg)
fmt.Println(markedSurrounded)
sentence := "I pull out things surrounded by abcWHOA COLORSdef"
markedSurrounded := marker.Mark(sentence, marker.MatchSurrounded("abc", "def"), magentaFg)
fmt.Println(markedSurrounded)
```
<img src="assets/png/matchsurrounded1.png">

#### MatchBracketSurrounded

```go
sentence = "[INFO] This is what log lines look like"
markedSurrounded = marker.Mark(sentence, marker.MatchBracketSurrounded(), redFg)
fmt.Println(markedSurrounded)
sentence = "[INFO] This is what log lines look like"
markedSurrounded = marker.Mark(sentence, marker.MatchBracketSurrounded(), redFg)
fmt.Println(markedSurrounded)
```
<img src="assets/png/matchsurrounded2.png">

#### MatchParensSurrounded

```go
sentence = "[ERROR] This is what (parens) lines look like"
markedSurrounded = marker.Mark(sentence, marker.MatchParensSurrounded(), blueFg)
fmt.Println(markedSurrounded)
sentence = "[ERROR] This is what (parens) lines look like"
markedSurrounded = marker.Mark(sentence, marker.MatchParensSurrounded(), blueFg)
fmt.Println(markedSurrounded)
```
<img src="assets/png/matchsurrounded3.png">

Expand All @@ -102,22 +102,70 @@ Marker has very simple and extensible way to get your strings colorful and brill
If you want to mark different patterns in the same string, marker builder is neater way to do this.

```go
rhyme := "I scream, you all scream, we all scream for ice cream."
b := &marker.MarkBuilder{}
r, _ := regexp.Compile("([a-z]?cream)")
rhyme := "I scream, you all scream, we all scream for ice cream."
b := &marker.MarkBuilder{}
r, _ := regexp.Compile("([a-z]?cream)")

markedWithBuilder := b.SetString(rhyme).
Mark(marker.MatchN("for ice", 1), color.New(color.FgRed)).
Mark(marker.MatchAll("all"), color.New(color.FgMagenta)).
Mark(marker.MatchRegexp(r), color.New(color.FgYellow)).
Build()
markedWithBuilder := b.SetString(rhyme).
Mark(marker.MatchN("for ice", 1), color.New(color.FgRed)).
Mark(marker.MatchAll("all"), color.New(color.FgMagenta)).
Mark(marker.MatchRegexp(r), color.New(color.FgYellow)).
Build()

fmt.Println(markedWithBuilder)
fmt.Println(markedWithBuilder)
```
<img src="assets/png/builder.png">

---

## Log way

You may want to instrument a logger such that any output coming from it is colorized in the expected manner. `marker` contains functionality which wraps `stdout` or whatever `io.Writer` you wish.

```go
stdoutMarker := marker.NewStdoutMarker()
markRules := []marker.MarkRule{
{marker.MatchBracketSurrounded(), color.New(color.FgBlue)},
{marker.MatchAll("marker"), color.New(color.FgRed)},
}

stdoutMarker.AddRules(markRules)
logger := log.New(stdoutMarker, "", 0)

logger.Println("[INFO] marker is working as expected")
```

<img src="assets/png/log.png">

### Customize io.Writer out for log interface

`marker` also allows you to specify the `io.Writer` that you want to send output to. This is useful if the logger is writing to somewhere other than `stdout` like a file.

```go
f, _ := os.Create("/tmp/awesome.log")
w := bufio.NewWriter(f)

writeMarker := marker.NewWriteMarker(w)

markRules := []marker.MarkRule{
{marker.MatchBracketSurrounded(), blueFg},
{marker.MatchAll("marker"), magentaFg},
}

writeMarker.AddRules(markRules)

logger := log.New(writeMarker, "", 0)
logger.Println("[INFO] colorful logs even in files, marker to mark them all!")

w.Flush()
f.Close()

output := catFile("/tmp/awesome.log") // cat /tmp/dat2
fmt.Print(output)
```

<img src="assets/png/logtofile.png">

## Writing your custom Matcher

As you see in above examples, **Mark** function takes an **MatcherFunc** to match the patterns in given string and colorize them.
Expand Down
Binary file removed assets/builder.jpg
Binary file not shown.
Binary file removed assets/matchall.jpg
Binary file not shown.
Binary file removed assets/matchn.jpg
Binary file not shown.
Binary file removed assets/matchregexp.jpg
Binary file not shown.
Binary file modified assets/png/builder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/png/custom.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/png/email.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/png/log.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/png/logtofile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/png/matchall.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/png/matchn.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/png/matchregex.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/png/matchsurrounded1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/png/matchsurrounded2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/png/matchsurrounded3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/png/showoff.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed assets/showoff.jpg
Binary file not shown.
Binary file removed assets/surrounded1.png
Binary file not shown.
Binary file removed assets/surrounded2.png
Binary file not shown.
Binary file removed assets/surrounded3.png
Binary file not shown.
27 changes: 27 additions & 0 deletions examples/log/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package main

import (
"log"

"github.com/cyucelen/marker"
"github.com/fatih/color"
)

var (
redFg = color.New(color.FgRed)
blueFg = color.New(color.FgBlue)
)

func main() {
stdoutMarker := marker.NewStdoutMarker()

markRules := []marker.MarkRule{
{marker.MatchBracketSurrounded(), blueFg},
{marker.MatchAll("marker"), redFg},
}

stdoutMarker.AddRules(markRules)

logger := log.New(stdoutMarker, "", 0)
logger.Println("[INFO] marker is working as expected")
}
52 changes: 52 additions & 0 deletions examples/logtofile/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package main

import (
"bufio"
"bytes"
"fmt"
"log"
"os"
"os/exec"

"github.com/cyucelen/marker"
"github.com/fatih/color"
)

var (
magentaFg = color.New(color.FgMagenta)
blueFg = color.New(color.FgBlue)
)

func main() {
f, _ := os.Create("/tmp/awesome.log")
w := bufio.NewWriter(f)

writeMarker := marker.NewWriteMarker(w)

markRules := []marker.MarkRule{
{marker.MatchBracketSurrounded(), blueFg},
{marker.MatchAll("marker"), magentaFg},
}

writeMarker.AddRules(markRules)

logger := log.New(writeMarker, "", 0)
logger.Println("[INFO] colorful logs even in files, marker to mark them all!")

w.Flush()
f.Close()

output := catFile("/tmp/awesome.log") // cat /tmp/dat2
fmt.Print(output)
}

func catFile(file string) string {
cmd := exec.Command("cat", file)
cmdOutput := &bytes.Buffer{}
cmd.Stdout = cmdOutput
err := cmd.Run()
if err != nil {
log.Fatalf("cmd.Run() failed with %s\n", err)
}
return string(cmdOutput.Bytes())
}
11 changes: 6 additions & 5 deletions examples/showoff/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package main

import (
"fmt"
"regexp"

"github.com/cyucelen/marker"
"github.com/fatih/color"
"regexp"
)

var magentaFg = color.New(color.FgMagenta)
Expand All @@ -30,16 +31,16 @@ func main() {

r, _ := regexp.Compile("([a-z]?cream)")
markedWithRegexp := marker.Mark(rhyme, marker.MatchRegexp(r), whiteFg.Add(color.BgHiBlue))
regexpExampleHeader := fmt.Sprintf("Mark Regexp \"%s\":\t\t\t\t", whiteFg.Add(color.BgHiBlue).Sprint("([a-z]?cream)"))
regexpExampleHeader := fmt.Sprintf("Mark Regexp \"%s\":\t\t\t", whiteFg.Add(color.BgHiBlue).Sprint("([a-z]?cream)"))
fmt.Println(regexpExampleHeader + markedWithRegexp)

b := &marker.MarkBuilder{}
markedWithBuilder := b.SetString(rhyme).
Mark(marker.MatchN("for ice", 1), redFg).
Mark(marker.MatchAll("all"), magentaFg).
Mark(marker.MatchRegexp(r), redFg.Add(color.BgHiWhite)).
Mark(marker.MatchRegexp(r), blueFg).
Build()
builderExampleHeader := fmt.Sprintf("Mark \"%s\", \"%s\", \"%s\" (w/ builder):\t",
color.New(color.FgRed).Sprint("for ice"), magentaFg.Sprint("all"), redFg.Add(color.BgHiWhite).Sprint("([a-z]?cream)"))
builderExampleHeader := fmt.Sprintf("Mark \"%s\", \"%s\", \"%s\" :\t",
color.New(color.FgRed).Sprint("for ice"), magentaFg.Sprint("all"), blueFg.Sprint("([a-z]?cream)"))
fmt.Println(builderExampleHeader + markedWithBuilder)
}
40 changes: 40 additions & 0 deletions image_generator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

# Terminal image generator

`generate.py` runs all the `main.go` files under examples and converts terminal outputs to `html` and then `png`

## Prerequisites

* Go
* Python3.7 (preferred)
* Pip

### terminal-to-html

```
$ cd ~/
$ go get github.com/buildkite/terminal-to-html/cmd/terminal-to-html
```

### wkhtmltoimage

#### Arch

```
$ yaourt wkhtmltopdf
```

#### Ubuntu

```
$ sudo apt-get update
$ sudo apt-get install xvfb libfontconfig wkhtmltopdf
```

## Usage

```
$ python3.7 generate.py
```

After running the script, image files should be created under `assets/png`
1 change: 1 addition & 0 deletions image_generator/log.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[INFO] marker is working as expected
54 changes: 54 additions & 0 deletions log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package marker

import (
"io"
"os"

"github.com/fatih/color"
)

// WriteMarkerOption is functional option type for WriteMarker
type WriteMarkerOption func(*WriteMarker)

// MarkRule contains marking information to be applied on log stream
type MarkRule struct {
Matcher MatcherFunc
Color *color.Color
}

// WriteMarker contains specified rules for applying them on output
type WriteMarker struct {
rules []MarkRule
out io.Writer
}

// NewWriteMarker creates a Marker that writes out to the given io.Writer
func NewWriteMarker(writer io.Writer) *WriteMarker {
logMarker := &WriteMarker{out: writer}
return logMarker
}

// NewStdoutMarker creates a WriteMarker with default out as os.Stdout
func NewStdoutMarker() *WriteMarker {
return NewWriteMarker(os.Stdout)
}

// AddRule appends a rule to WriteMarker and returns itself
func (s *WriteMarker) AddRule(rule MarkRule) *WriteMarker {
s.rules = append(s.rules, rule)
return s
}

// AddRules appends all rules from given slice to WriteMarker rules
func (s *WriteMarker) AddRules(rules []MarkRule) {
s.rules = append(s.rules, rules...)
}

// Write marks the text with specified rules and writes the output to specifed out
func (s WriteMarker) Write(p []byte) (n int, err error) {
marked := string(p)
for _, rule := range s.rules {
marked = Mark(marked, rule.Matcher, rule.Color)
}
return s.out.Write([]byte(marked))
jnatalzia marked this conversation as resolved.
Show resolved Hide resolved
}
Loading