From fdf7108321d4747d14e8f51109e4139ebc4db0e1 Mon Sep 17 00:00:00 2001 From: Sergey Grebenshchikov Date: Sat, 28 Apr 2018 18:47:25 +0200 Subject: [PATCH] Breaking changes: - Use UTC timezone by default (instead of local) - *Delta* builtin templates now print string deltas - .tar.gz releases for osx and linux instead of .zip Additions: - ISO8601 builtin time format - DeltaColor builtin template - *DeltaNanos* builtin templates that print nanoseconds (like *Delta* did previously) - 32-bit and ARM releases --- Makefile | 96 ++++++++++---- README.md | 46 ++++--- README.template.md | 310 +++++++++++++++++++++++++++++++++++++++++++++ cmd/tj/main.go | 22 ++-- 4 files changed, 421 insertions(+), 53 deletions(-) create mode 100644 README.template.md diff --git a/Makefile b/Makefile index 3d0ba9c..17fc58d 100644 --- a/Makefile +++ b/Makefile @@ -1,50 +1,92 @@ -VERSION = 6.0.2 +VERSION = 7.0.0 +APP := tj PACKAGES := $(shell go list -f {{.Dir}} ./...) GOFILES := $(addsuffix /*.go,$(PACKAGES)) GOFILES := $(wildcard $(GOFILES)) -.PHONY: clean release docker docker-latest +.PHONY: clean release release-ci release-manual docker docker-latest README.md + +clean: + rm -rf binaries/ + rm -rf release/ + +release-ci: README.md zip + +release: README.md + git reset + git add README.md + git add Makefile + git commit -am "Release $(VERSION)" || true + git tag "$(VERSION)" + git push + git push origin "$(VERSION)" # go get -u github.com/github/hub -release: zip +release-manual: README.md zip git push - hub release delete $(VERSION) || true - hub release create $(VERSION) -m "$(VERSION)" -a release/tj_$(VERSION)_osx_x86_64.zip -a release/tj_$(VERSION)_windows_x86_64.zip -a release/tj_$(VERSION)_linux_x86_64.zip + hub release create $(VERSION) -m "$(VERSION)" -a release/$(APP)_$(VERSION)_osx_x86_64.tar.gz -a release/$(APP)_$(VERSION)_windows_x86_64.zip -a release/$(APP)_$(VERSION)_linux_x86_64.tar.gz -a release/$(APP)_$(VERSION)_osx_x86_32.tar.gz -a release/$(APP)_$(VERSION)_windows_x86_32.zip -a release/$(APP)_$(VERSION)_linux_x86_32.tar.gz -a release/$(APP)_$(VERSION)_linux_arm64.tar.gz + +README.md: + sed "s/\$${VERSION}/$(VERSION)/g;s/\$${APP}/$(APP)/g;" README.template.md > README.md -docker: binaries/linux_x86_64/tj - docker build -t quay.io/sergey_grebenshchikov/tj:v$(VERSION) . - docker push quay.io/sergey_grebenshchikov/tj:v$(VERSION) +docker: binaries/linux_x86_64/$(APP) + docker build -t quay.io/sergey_grebenshchikov/$(APP):v$(VERSION) . + docker push quay.io/sergey_grebenshchikov/$(APP):v$(VERSION) docker-latest: docker - docker tag quay.io/sergey_grebenshchikov/tj:v$(VERSION) quay.io/sergey_grebenshchikov/tj:latest - docker push quay.io/sergey_grebenshchikov/tj:latest + docker tag quay.io/sergey_grebenshchikov/$(APP):v$(VERSION) quay.io/sergey_grebenshchikov/$(APP):latest + docker push quay.io/sergey_grebenshchikov/$(APP):latest -zip: release/tj_$(VERSION)_osx_x86_64.zip release/tj_$(VERSION)_windows_x86_64.zip release/tj_$(VERSION)_linux_x86_64.zip +zip: release/$(APP)_$(VERSION)_osx_x86_64.tar.gz release/$(APP)_$(VERSION)_windows_x86_64.zip release/$(APP)_$(VERSION)_linux_x86_64.tar.gz release/$(APP)_$(VERSION)_osx_x86_32.tar.gz release/$(APP)_$(VERSION)_windows_x86_32.zip release/$(APP)_$(VERSION)_linux_x86_32.tar.gz release/$(APP)_$(VERSION)_linux_arm64.tar.gz -binaries: binaries/osx_x86_64/tj binaries/windows_x86_64/tj.exe binaries/linux_x86_64/tj +binaries: binaries/osx_x86_64/$(APP) binaries/windows_x86_64/$(APP).exe binaries/linux_x86_64/$(APP) binaries/osx_x86_32/$(APP) binaries/windows_x86_32/$(APP).exe binaries/linux_x86_32/$(APP) -clean: - rm -rf binaries/ - rm -rf release/ +release/$(APP)_$(VERSION)_osx_x86_64.tar.gz: binaries/osx_x86_64/$(APP) + mkdir -p release + tar cfz release/$(APP)_$(VERSION)_osx_x86_64.tar.gz -C binaries/osx_x86_64 $(APP) + +binaries/osx_x86_64/$(APP): $(GOFILES) + GOOS=darwin GOARCH=amd64 go build -ldflags "-X main.version=$(VERSION)" -o binaries/osx_x86_64/$(APP) ./cmd/$(APP) + +release/$(APP)_$(VERSION)_windows_x86_64.zip: binaries/windows_x86_64/$(APP).exe + mkdir -p release + cd ./binaries/windows_x86_64 && zip -r -D ../../release/$(APP)_$(VERSION)_windows_x86_64.zip $(APP).exe + +binaries/windows_x86_64/$(APP).exe: $(GOFILES) + GOOS=windows GOARCH=amd64 go build -ldflags "-X main.version=$(VERSION)" -o binaries/windows_x86_64/$(APP).exe ./cmd/$(APP) + +release/$(APP)_$(VERSION)_linux_x86_64.tar.gz: binaries/linux_x86_64/$(APP) + mkdir -p release + tar cfz release/$(APP)_$(VERSION)_linux_x86_64.tar.gz -C binaries/linux_x86_64 $(APP) + +binaries/linux_x86_64/$(APP): $(GOFILES) + GOOS=linux GOARCH=amd64 go build -ldflags "-X main.version=$(VERSION)" -o binaries/linux_x86_64/$(APP) ./cmd/$(APP) + +release/$(APP)_$(VERSION)_osx_x86_32.tar.gz: binaries/osx_x86_32/$(APP) + mkdir -p release + tar cfz release/$(APP)_$(VERSION)_osx_x86_32.tar.gz -C binaries/osx_x86_32 $(APP) + +binaries/osx_x86_32/$(APP): $(GOFILES) + GOOS=darwin GOARCH=386 go build -ldflags "-X main.version=$(VERSION)" -o binaries/osx_x86_32/$(APP) ./cmd/$(APP) -release/tj_$(VERSION)_osx_x86_64.zip: binaries/osx_x86_64/tj +release/$(APP)_$(VERSION)_windows_x86_32.zip: binaries/windows_x86_32/$(APP).exe mkdir -p release - cd ./binaries/osx_x86_64 && zip -r -D ../../release/tj_$(VERSION)_osx_x86_64.zip tj + cd ./binaries/windows_x86_32 && zip -r -D ../../release/$(APP)_$(VERSION)_windows_x86_32.zip $(APP).exe -binaries/osx_x86_64/tj: $(GOFILES) - GOOS=darwin GOARCH=amd64 go build -ldflags "-X main.version=$(VERSION)" -o binaries/osx_x86_64/tj ./cmd/tj +binaries/windows_x86_32/$(APP).exe: $(GOFILES) + GOOS=windows GOARCH=386 go build -ldflags "-X main.version=$(VERSION)" -o binaries/windows_x86_32/$(APP).exe ./cmd/$(APP) -release/tj_$(VERSION)_windows_x86_64.zip: binaries/windows_x86_64/tj.exe +release/$(APP)_$(VERSION)_linux_x86_32.tar.gz: binaries/linux_x86_32/$(APP) mkdir -p release - cd ./binaries/windows_x86_64 && zip -r -D ../../release/tj_$(VERSION)_windows_x86_64.zip tj.exe + tar cfz release/$(APP)_$(VERSION)_linux_x86_32.tar.gz -C binaries/linux_x86_32 $(APP) -binaries/windows_x86_64/tj.exe: $(GOFILES) - GOOS=windows GOARCH=amd64 go build -ldflags "-X main.version=$(VERSION)" -o binaries/windows_x86_64/tj.exe ./cmd/tj +binaries/linux_x86_32/$(APP): $(GOFILES) + GOOS=linux GOARCH=386 go build -ldflags "-X main.version=$(VERSION)" -o binaries/linux_x86_32/$(APP) ./cmd/$(APP) -release/tj_$(VERSION)_linux_x86_64.zip: binaries/linux_x86_64/tj +release/$(APP)_$(VERSION)_linux_arm64.tar.gz: binaries/linux_arm64/$(APP) mkdir -p release - cd ./binaries/linux_x86_64 && zip -r -D ../../release/tj_$(VERSION)_linux_x86_64.zip tj + tar cfz release/$(APP)_$(VERSION)_linux_arm64.tar.gz -C binaries/linux_arm64 $(APP) -binaries/linux_x86_64/tj: $(GOFILES) - GOOS=linux GOARCH=amd64 go build -ldflags "-X main.version=$(VERSION)" -o binaries/linux_x86_64/tj ./cmd/tj \ No newline at end of file +binaries/linux_arm64/$(APP): $(GOFILES) + GOOS=linux GOARCH=arm64 go build -ldflags "-X main.version=$(VERSION)" -o binaries/linux_arm64/$(APP) ./cmd/$(APP) diff --git a/README.md b/README.md index d9da679..d0ae494 100644 --- a/README.md +++ b/README.md @@ -24,18 +24,24 @@ Using go get: go get -u github.com/sgreben/tj/cmd/tj ``` -Or [download the binary](https://github.com/sgreben/tj/releases/latest) from the releases page. - -Also available as a [docker image](https://quay.io/repository/sergey_grebenshchikov/tj?tab=tags): +Or [download the binary](https://github.com/sgreben/tj/releases/latest) from the releases page: ```bash -docker pull quay.io/sergey_grebenshchikov/tj +# Linux +curl -L https://github.com/sgreben/tj/releases/download/7.0.0/tj_7.0.0_linux_x86_64.tar.gz | tar xz + +# OS X +curl -L https://github.com/sgreben/tj/releases/download/7.0.0/tj_7.0.0_osx_x86_64.tar.gz | tar xz + +# Windows +curl -LO https://github.com/sgreben/tj/releases/download/7.0.0/tj_7.0.0_windows_x86_64.zip +unzip tj_7.0.0_windows_x86_64.zip ``` -Or using [docker-get](https://github.com/32b/docker-get): +Also available as a [docker image](https://quay.io/repository/sergey_grebenshchikov/tj?tab=tags): ```bash -docker-get https://github.com/sgreben/tj +docker pull quay.io/sergey_grebenshchikov/tj ``` ## Use it @@ -49,7 +55,7 @@ Usage of tj: -time-format string either a go time format string or one of the predefined format names (https://golang.org/pkg/time/#pkg-constants) -time-zone string - time zone to use (default "Local") + time zone to use (or "Local") (default "UTC") -match-regex string a regex pattern. if given, only tokens matching it (re)start the stopwatch -match-template string @@ -113,12 +119,13 @@ $ (echo Hello; echo World) | tj -time-format Kitchen {"timeSecs":1517592194,"timeNanos":1517592194875197515,"time":"6:23PM","deltaSecs":0.000180876,"deltaNanos":180876,"delta":"180.876µs","totalSecs":0.000198018,"totalNanos":198018,"total":"198.018µs","text":"World"} ``` -The [constant names from pkg/time](https://golang.org/pkg/time/#pkg-constants) as well as regular go time layouts are admissible values for `-time-format`: +The [constant names from pkg/time](https://golang.org/pkg/time/#pkg-constants) as well as regular go time layouts are valid values for `-time-format`: | Name | Format | |------------|-------------------------------------| | ANSIC | `Mon Jan _2 15:04:05 2006` | | Kitchen | `3:04PM` | +| ISO8601 | `2006-01-02T15:04:05Z07:00` | | RFC1123 | `Mon, 02 Jan 2006 15:04:05 MST` | | RFC1123Z | `Mon, 02 Jan 2006 15:04:05 -0700` | | RFC3339 | `2006-01-02T15:04:05Z07:00` | @@ -150,15 +157,18 @@ The fields available to the template are specified in the [`token` struct](cmd/t Some templates are pre-defined and can be used via `-template NAME`: -| Name | Template | -|------------|--------------------------------------------------| -| Color | `{{color .}}█{{reset}} {{.Text}}` | -| ColorText | `{{color .}}{{.Text}}{{reset}}` | -| Delta | `{{.DeltaNanos}} {{.Text}}` | -| Text | `{{.Text}}` | -| Time | `{{.TimeString}} {{.Text}}` | -| TimeDelta | `{{.TimeString}} +{{.DeltaNanos}} {{.Text}}` | -| TimeColor | `{{.TimeString}} {{color .}}█{{reset}} {{.Text}}`| +| Name | Template | +|-----------------|--------------------------------------------------| +| Color | `{{color .}}█{{reset}} {{.Text}}` | +| ColorText | `{{color .}}{{.Text}}{{reset}}` | +| Delta | `{{.Delta}} {{.Text}}` | +| DeltaColor | `{{.Delta}} {{color .}}█{{reset}} {{.Text}}` | +| DeltaNanos | `{{.DeltaNanos}} {{.Text}}` | +| Text | `{{.Text}}` | +| Time | `{{.TimeString}} {{.Text}}` | +| TimeColor | `{{.TimeString}} {{color .}}█{{reset}} {{.Text}}`| +| TimeDelta | `{{.TimeString}} +{{.Delta}} {{.Text}}` | +| TimeDeltaNanos | `{{.TimeString}} +{{.DeltaNanos}} {{.Text}}` | ### Color output @@ -297,4 +307,4 @@ $ docker build . | ## Comments -Feel free to [leave a comment](https://github.com/sgreben/tj/issues/1) or create an issue. \ No newline at end of file +Feel free to [leave a comment](https://github.com/sgreben/tj/issues/1) or create an issue. diff --git a/README.template.md b/README.template.md new file mode 100644 index 0000000..2a1e503 --- /dev/null +++ b/README.template.md @@ -0,0 +1,310 @@ +# tj - stdin line timestamps, JSON-friendly + +`tj` timestamps lines read from standard input. + +- [Get it](#get-it) +- [Use it](#use-it) + - [JSON output](#json-output) + - [Time format](#time-format) + - [Template output](#template-output) + - [Color output](#color-output) + - [JSON input](#json-input) + - [Stopwatch regex](#stopwatch-regex) + - [Stopwatch regex template](#stopwatch-regex-template) + - [Stopwatch condition](#stopwatch-condition) +- [Example](#example) +- [Comments](https://github.com/sgreben/tj/issues/1) + + +## Get it + +Using go get: + +```bash +go get -u github.com/sgreben/tj/cmd/tj +``` + +Or [download the binary](https://github.com/sgreben/tj/releases/latest) from the releases page: + +```bash +# Linux +curl -L https://github.com/sgreben/tj/releases/download/${VERSION}/tj_${VERSION}_linux_x86_64.tar.gz | tar xz + +# OS X +curl -L https://github.com/sgreben/tj/releases/download/${VERSION}/tj_${VERSION}_osx_x86_64.tar.gz | tar xz + +# Windows +curl -LO https://github.com/sgreben/tj/releases/download/${VERSION}/tj_${VERSION}_windows_x86_64.zip +unzip tj_${VERSION}_windows_x86_64.zip +``` + +Also available as a [docker image](https://quay.io/repository/sergey_grebenshchikov/tj?tab=tags): + +```bash +docker pull quay.io/sergey_grebenshchikov/tj +``` + +## Use it + +`tj` reads from stdin and writes to stdout. + +```text +Usage of tj: + -template string + either a go template (https://golang.org/pkg/text/template) or one of the predefined template names + -time-format string + either a go time format string or one of the predefined format names (https://golang.org/pkg/time/#pkg-constants) + -time-zone string + time zone to use (or "Local") (default "UTC") + -match-regex string + a regex pattern. if given, only tokens matching it (re)start the stopwatch + -match-template string + go template, used to extract text used for -match-regex + -match-condition string + go template. if given, only tokens that result in 'true' (re)start the stopwatch + -match-buffer + buffer lines between matches of -match-regex / -match-condition, copy delta values from final line to buffered lines + -match string + alias for -match-template + -condition string + alias for -match-condition + -regex string + alias for -match-regex + -read-json + parse a sequence of JSON objects from stdin + -scale string + either a sequence of hex colors or one of the predefined color scale names (colors go from fast to slow) + (default "BlueToRed") + -scale-fast duration + the lower bound for the color scale (default 100ms) + -scale-slow duration + the upper bound for the color scale (default 2s) + -scale-linear + use linear scale (default true) + -scale-cube + use cubic scale + -scale-cubert + use cubic root scale + -scale-sqr + use quadratic scale + -scale-sqrt + use quadratic root scale + -version + print version and exit +``` + +### JSON output + +The default output format is JSON, one object per line: + +```bash +$ (echo Hello; echo World) | tj +``` + +```json +{"timeSecs":1517592179,"timeNanos":1517592179895262811,"time":"2018-02-02T18:22:59+01:00","deltaSecs":0.000016485,"deltaNanos":16485,"delta":"16.485µs","totalSecs":0.000016485,"totalNanos":16485,"total":"16.485µs","text":"Hello"} +{"timeSecs":1517592179,"timeNanos":1517592179895451948,"time":"2018-02-02T18:22:59+01:00","deltaSecs":0.000189137,"deltaNanos":189137,"delta":"189.137µs","totalSecs":0.000205622,"totalNanos":205622,"total":"205.622µs","text":"World"} +``` + +### Time format + +You can set the format of the `time` field using the `-time-format` parameter: + +```bash +$ (echo Hello; echo World) | tj -time-format Kitchen +``` + +```json +{"timeSecs":1517592194,"timeNanos":1517592194875016639,"time":"6:23PM","deltaSecs":0.000017142,"deltaNanos":17142,"delta":"17.142µs","totalSecs":0.000017142,"totalNanos":17142,"total":"17.142µs","text":"Hello"} +{"timeSecs":1517592194,"timeNanos":1517592194875197515,"time":"6:23PM","deltaSecs":0.000180876,"deltaNanos":180876,"delta":"180.876µs","totalSecs":0.000198018,"totalNanos":198018,"total":"198.018µs","text":"World"} +``` + +The [constant names from pkg/time](https://golang.org/pkg/time/#pkg-constants) as well as regular go time layouts are valid values for `-time-format`: + +| Name | Format | +|------------|-------------------------------------| +| ANSIC | `Mon Jan _2 15:04:05 2006` | +| Kitchen | `3:04PM` | +| ISO8601 | `2006-01-02T15:04:05Z07:00` | +| RFC1123 | `Mon, 02 Jan 2006 15:04:05 MST` | +| RFC1123Z | `Mon, 02 Jan 2006 15:04:05 -0700` | +| RFC3339 | `2006-01-02T15:04:05Z07:00` | +| RFC3339Nano| `2006-01-02T15:04:05.999999999Z07:00` +| RFC822 | `02 Jan 06 15:04 MST` | +| RFC822Z | `02 Jan 06 15:04 -0700` | +| RFC850 | `Monday, 02-Jan-06 15:04:05 MST` | +| RubyDate | `Mon Jan 02 15:04:05 -0700 2006` | +| Stamp | `Jan _2 15:04:05` | +| StampMicro | `Jan _2 15:04:05.000000` | +| StampMilli | `Jan _2 15:04:05.000` | +| StampNano | `Jan _2 15:04:05.000000000` | +| UnixDate | `Mon Jan _2 15:04:05 MST 2006` | + +### Template output + +You can also specify an output template using the `-template` parameter and [go template](https://golang.org/pkg/text/template) syntax: + +```bash +$ (echo Hello; echo World) | tj -template '{{ .I }} {{.TimeSecs}} {{.Text}}' +``` + +```json +0 1516649679 Hello +1 1516649679 World +``` + +The fields available to the template are specified in the [`token` struct](cmd/tj/main.go#L18). + +Some templates are pre-defined and can be used via `-template NAME`: + +| Name | Template | +|-----------------|--------------------------------------------------| +| Color | `{{color .}}█{{reset}} {{.Text}}` | +| ColorText | `{{color .}}{{.Text}}{{reset}}` | +| Delta | `{{.Delta}} {{.Text}}` | +| DeltaColor | `{{.Delta}} {{color .}}█{{reset}} {{.Text}}` | +| DeltaNanos | `{{.DeltaNanos}} {{.Text}}` | +| Text | `{{.Text}}` | +| Time | `{{.TimeString}} {{.Text}}` | +| TimeColor | `{{.TimeString}} {{color .}}█{{reset}} {{.Text}}`| +| TimeDelta | `{{.TimeString}} +{{.Delta}} {{.Text}}` | +| TimeDeltaNanos | `{{.TimeString}} +{{.DeltaNanos}} {{.Text}}` | + +### Color output + +To help identify durations at a glance, `tj` maps durations to a color scale. The pre-defined templates `Color` and `ColorText` demonstrate this: + +```bash +$ (echo fast; + sleep 1; + echo slower; + sleep 1.5; + echo slow; + sleep 2; + echo slowest) | tj -template Color +``` +![Color output](docs/images/colors.png) + +The terminal foreground color can be set by using `{{color .}}` in the output template. The default terminal color can be restored using `{{reset}}`. + +The color scale can be set using the parameters `-scale`, `-scale-fast`, and `-scale-slow`: + +- The `-scale` parameter defines the colors used in the scale. +- The `-scale-fast` and `-scale-slow` parameters define the boundaries of the scale: durations shorter than the value of `-scale-fast` are mapped to the leftmost color, durations longer than the value of `-scale-slow` are mapped to the rightmost color. + +The scale is linear by default, but can be transformed: + +- `-scale-sqr`, `-scale-sqrt` yields a quadratic (root) scale +- `-scale-cube`, `-scale-cubert` yields a cubic (root) scale + +There are several pre-defined color scales: + +| Name | Scale | +|---------------------|----------------------- | +| BlackToPurple | `#000 -> #F700FF` | +| BlackToRed | `#000 -> #F00` | +| BlueToRed | `#00F -> #F00` | +| CyanToRed | `#0FF -> #F00` | +| GreenToRed | `#0F0 -> #F00` | +| GreenToGreenToRed | `#0F0 -> #0F0 -> #F00` | +| WhiteToPurple | `#FFF -> #F700FF` | +| WhiteToRed | `#FFF -> #F00` | +| WhiteToBlueToRed | `#FFF -> #00F -> #F00` | + +You can also provide your own color scale using the same syntax as the pre-defined ones. + +### JSON input + +Using `-read-json`, you can tell `tj` to parse stdin as a sequence of JSON objects. The parsed object can be referred to via `.Object`, like this: + +```bash +$ echo '{"hello": "World"}' | tj -read-json -template "{{.TimeString}} {{.Object.hello}}" +``` + +``` +2018-01-25T21:55:06+01:00 World +``` + +The exact JSON string that was parsed can be recovered using `.Text`: + +```bash +$ echo '{"hello" : "World"} { }' | tj -read-json -template "{{.TimeString}} {{.Text}}" +``` + +``` +2018-01-25T21:55:06+01:00 {"hello" : "World"} +2018-01-25T21:55:06+01:00 { } +``` + +### Stopwatch regex + +Sometimes you need to measure the duration between certain *tokens* in the input. + +To help with this, `tj` can match each line against a regular expression and only reset the stopwatch (`delta`, `deltaSecs`, `deltaNanos`) when a line matches. The regular expression can be specified via the `-match-regex` (alias `-regex`) parameter. + +### Stopwatch regex template + +When using `-match-regex`, you can also specify a template `-match-template` (alias `-match`) to extract text from the current token. The output of this template is matched against the stopwatch regex. + +This allows you to use only specific fields of JSON objects as stopwatch reset triggers. For example: + +```bash +$ (echo {}; sleep 1; echo {}; sleep 1; echo '{"reset": "yes"}'; echo {}) | + tj -read-json -match .reset -regex yes -template "{{.I}} {{.DeltaNanos}}" +``` + +``` +0 14374 +1 1005916918 +2 2017292187 +3 79099 +``` + +The output of the match template is stored in the field `.MatchText` of the `token` struct: + +```bash +$ echo '{"message":"hello"}' | tj -read-json -match-template .message -template "{{.TimeString}} {{.MatchText}}" +``` + +``` +2018-01-25T22:20:59+01:00 hello +``` + +### Stopwatch condition + +Additionally to `-match-regex`, you can specify a `-match-condition` go template. If this template produces the literal string `true`, the stopwatch is reset - "matches" of the `-match-condition` are treated like matches of the `-match-regex`. + +## Example + +Finding the slowest step in a `docker build` (using `jq`): + +```bash +$ cat Dockerfile +FROM alpine +RUN echo About to be slow... +RUN sleep 10 +RUN echo Done being slow +``` + +```bash +$ docker build . | + tj -regex ^Step | + jq -s 'max_by(.deltaNanos) | {step:.start.text, duration:.delta}' +``` + +```json +{"step":"Step 3/4 : RUN sleep 10","duration":"10.602026127s"} +``` + +Alternatively, using color output and buffering: + +```bash +$ docker build . | + tj -regex ^Step -match-buffer -template Color -scale-cube +``` + +![Docker build with color output](docs/images/docker.png) + +## Comments + +Feel free to [leave a comment](https://github.com/sgreben/tj/issues/1) or create an issue. \ No newline at end of file diff --git a/cmd/tj/main.go b/cmd/tj/main.go index e297840..46c6a5a 100644 --- a/cmd/tj/main.go +++ b/cmd/tj/main.go @@ -80,6 +80,8 @@ func print(data interface{}) { } } +const ISO8601 = "2006-01-02T15:04:05Z07:00" + var timeFormats = map[string]string{ "ANSIC": time.ANSIC, "UnixDate": time.UnixDate, @@ -90,6 +92,7 @@ var timeFormats = map[string]string{ "RFC1123": time.RFC1123, "RFC1123Z": time.RFC1123Z, "RFC3339": time.RFC3339, + "ISO8601": ISO8601, "RFC3339Nano": time.RFC3339Nano, "Kitchen": time.Kitchen, "Stamp": time.Stamp, @@ -99,13 +102,16 @@ var timeFormats = map[string]string{ } var templates = map[string]string{ - "Text": "{{.Text}}", - "Time": "{{.TimeString}} {{.Text}}", - "TimeDelta": "{{.TimeString}} +{{.DeltaNanos}} {{.Text}}", - "Delta": "{{.DeltaNanos}} {{.Text}}", - "ColorText": "{{color .}}{{.Text}}{{reset}}", - "Color": "{{color .}}█{{reset}} {{.Text}}", - "TimeColor": "{{.TimeString}} {{color .}}█{{reset}} {{.Text}}", + "Text": "{{.Text}}", + "Time": "{{.TimeString}} {{.Text}}", + "TimeDeltaNanos": "{{.TimeString}} +{{.DeltaNanos}} {{.Text}}", + "TimeDelta": "{{.TimeString}} +{{.Delta}} {{.Text}}", + "DeltaNanos": "{{.DeltaNanos}} {{.Text}}", + "Delta": "{{.Delta}} {{.Text}}", + "ColorText": "{{color .}}{{.Text}}{{reset}}", + "Color": "{{color .}}█{{reset}} {{.Text}}", + "DeltaColor": "{{.Delta}} {{color .}}█{{reset}} {{.Text}}", + "TimeColor": "{{.TimeString}} {{color .}}█{{reset}} {{.Text}}", } var colorScales = map[string]string{ @@ -183,7 +189,7 @@ func addTemplateDelimitersIfLiteral(t string) string { func init() { flag.StringVar(&config.template, "template", "", templatesHelp()) flag.StringVar(&config.timeFormat, "time-format", "RFC3339", timeFormatsHelp()) - flag.StringVar(&config.timeZone, "time-zone", "Local", "time zone to use") + flag.StringVar(&config.timeZone, "time-zone", "UTC", `time zone to use (or "Local")`) flag.StringVar(&config.matchRegex, "regex", "", "alias for -match-regex") flag.StringVar(&config.matchRegex, "match-regex", "", "a regex pattern. if given, only tokens matching it (re)start the stopwatch") flag.StringVar(&config.matchCondition, "condition", "", "alias for -match-condition")