Skip to content

Commit 8d8da91

Browse files
committed
Merge branch 'release/1.0.2'
2 parents 00c2493 + 7211da4 commit 8d8da91

23 files changed

+519
-77
lines changed

.gitignore

+9
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,12 @@
1515
/publish
1616
/VERSION
1717
/build
18+
/logs/workflow.json
19+
/logs/trapper.json
20+
/logs/sleep.json
21+
/logs/piper.json
22+
/logs/false.json
23+
/logs/fail.json
24+
/logs/env.json
25+
/logs/dropcheck.json
26+
/logs/arger.json

Gopkg.lock

+9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

+58
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ The following attributes can be set for the workflow:
160160
| version | Workflow format version | `1` |
161161
| version | Any metadata for the workflow | None |
162162
| steps | List of all workflow steps (See below) | [] |
163+
| logger | Workflow Logger | Default Logger (see below) |
164+
| SessionID | Auto generated 8 digit value for each run of the workflow | |
163165

164166
## Step Attributes
165167

@@ -180,6 +182,7 @@ The following attributes can be set for each step:
180182
| show_command | Shows the command and arguments for this step before running it | `false` |
181183
| disabled | Disables the step (doesn't run it). This can be used for debugging or other selective workflow manipulations | `false` |
182184
| env | Environment variables specific to this step | [] |
185+
| logger | Step logger | Workflow logger (see below) |
183186

184187
## Trackman CLI
185188

@@ -191,6 +194,9 @@ The CLI supports the following global options:
191194
|---|---|---|
192195
| config | Config file | $HOME/.trackman.yaml |
193196
| log-level | Log level | `info` |
197+
| log-type | Log Type. Valid options are `stdout`, `stderr`, `discard`, `file` | `stdout` |
198+
| log-format | Log Format. Valid options are `text` and `json` | `text` |
199+
| log-file | Log File. If `file` is used as `log-type` then this is used as the filename (path can be included) | |
194200
| no-update | Don't update trackman CLI automatically | `false` |
195201

196202
### Run
@@ -212,6 +218,58 @@ Run command supports the following options
212218
| concurrency | Number of concurrent steps to run | Number of CPUs - 1 |
213219
| yes, y | Answer Yes to all `ask_to_proceed` questions | false |
214220

221+
### Logging
222+
223+
By default, trackman logs all output to `stdout` and at the `info` level. All logs from all steps are also combined and shown together as they are produced.
224+
225+
You can specify log configuration at the workflow level or for each individual step. If a step has no specific log configuration, it will inherit the configuration of the workflow. Preflight and Probes use the same log configuration as their step.
226+
227+
Log configuration can be defined with the following options:
228+
229+
| Option | Description | Default |
230+
|---|---|---|
231+
| type | Logger Type. Valid options are `stdout`, `stderr`, `discard` and `file` | `stdout` |
232+
| level | Log level. Valid values are `error`, `warn`, `info` and `debug` | `info` |
233+
| format | Log Format. Valid options are `text` and `json` | `text` |
234+
| destination | Log file (can include path). If type is `file` this is used as the file name. If no path is provided, the current directory is used. | |
235+
236+
Here is an example:
237+
238+
```yaml
239+
version: 1
240+
logger:
241+
type: "file"
242+
format: "json"
243+
destination: "workflow.json"
244+
steps:
245+
- name: step1
246+
logger:
247+
type: "stdout"
248+
- name: step2
249+
```
250+
251+
In the example above, the workflow and step2 share a file called `workflow.json` for logging. Step1 however will log text to `stdout`.
252+
253+
You can use any attribute from Workflow and Step in naming your log file. Here is an example:
254+
255+
```yaml
256+
version: 1
257+
logger:
258+
type: "file"
259+
format: "json"
260+
destination: "logs/{{ if .Step }}{{.Step.Name}}{{ else }}workflow{{ end }}.json"
261+
```
262+
263+
The example above, will use `workflow.json` for workflow logs but a file named after the step name for each step. You can use Golang templates for this feature. The template is rendered with a context of `Workflow` and `Step` (in the example above, `.Step` is used)
264+
265+
Another example is to use the Workflow SessionID as log file name:
266+
267+
```yaml
268+
version: 1
269+
logger:
270+
type: "file"
271+
destination: "logs/{{.Workflow.SessionID}}.log"
272+
```
215273

216274
### Update
217275

cmd/root.go

+6
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,15 @@ func init() {
2929
cobra.OnInitialize(initConfig)
3030
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.trackman.yaml)")
3131
rootCmd.PersistentFlags().String("log-level", "info", "log level. Use debug to see process output")
32+
rootCmd.PersistentFlags().String("log-type", "stdout", "log type. Valid values are stdout, stderr, discard and file")
33+
rootCmd.PersistentFlags().String("log-format", "text", "log format. Valid values are text and json")
34+
rootCmd.PersistentFlags().String("log-file", "trackman.log", "file path for logs. Only used when log-type is file")
3235
rootCmd.PersistentFlags().Bool("no-update", false, "turn off auto update")
3336

3437
_ = viper.BindPFlag("log-level", rootCmd.PersistentFlags().Lookup("log-level"))
38+
_ = viper.BindPFlag("log-file", rootCmd.PersistentFlags().Lookup("log-file"))
39+
_ = viper.BindPFlag("log-type", rootCmd.PersistentFlags().Lookup("log-type"))
40+
_ = viper.BindPFlag("log-format", rootCmd.PersistentFlags().Lookup("log-format"))
3541
_ = viper.BindPFlag("no-update", rootCmd.PersistentFlags().Lookup("no-update"))
3642
}
3743

cmd/run.go

+6-9
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010

1111
"github.com/cloud66-oss/trackman/notifiers"
1212
"github.com/cloud66-oss/trackman/utils"
13-
"github.com/sirupsen/logrus"
1413
"github.com/spf13/cobra"
1514
"github.com/spf13/viper"
1615
)
@@ -40,14 +39,6 @@ func init() {
4039

4140
func runExec(cmd *cobra.Command, args []string) {
4241
ctx := context.Background()
43-
level, err := logrus.ParseLevel(viper.GetString("log-level"))
44-
if err != nil {
45-
fmt.Println(err)
46-
os.Exit(1)
47-
}
48-
49-
ctx = context.WithValue(ctx, utils.CtxLogLevel, level)
50-
logger, ctx := utils.LoggerContext(ctx)
5142

5243
options := &utils.WorkflowOptions{
5344
Notifier: notifiers.ConsoleNotify,
@@ -61,6 +52,12 @@ func runExec(cmd *cobra.Command, args []string) {
6152
os.Exit(1)
6253
}
6354

55+
logger, err := utils.NewLogger(workflow.Logger, utils.NewLoggingContext(workflow, nil))
56+
if err != nil {
57+
fmt.Println(err)
58+
os.Exit(1)
59+
}
60+
6461
err, stepErrors := workflow.Run(ctx)
6562
if err != nil {
6663
logger.Error(err)

logs/.keep

Whitespace-only changes.

main.go

+3
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@ import (
55
"time"
66

77
"github.com/cloud66-oss/trackman/cmd"
8+
"github.com/cloud66-oss/trackman/utils"
89
)
910

1011
func main() {
1112
defer func() {
13+
utils.CloseAllFiles()
14+
1215
c := make(chan struct{})
1316
go func() {
1417
defer close(c)

notifiers/console_notifier.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@ import (
44
"context"
55

66
"github.com/cloud66-oss/trackman/utils"
7+
"github.com/sirupsen/logrus"
78
)
89

910
// ConsoleNotify writes notifications to console
10-
func ConsoleNotify(ctx context.Context, event *utils.Event) error {
11-
logger, _ := utils.LoggerContext(ctx)
12-
11+
func ConsoleNotify(ctx context.Context, logger *logrus.Logger, event *utils.Event) error {
1312
switch event.Name {
1413
case utils.EventRunRequested:
1514
logger.WithField(utils.FldStep, event.Payload.Spinner.Name).Info("Starting")

samples/logging.yml

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
version: 1
2+
metadata:
3+
cloud66.com/uuid: ff97e4c6
4+
cloud66.com/test: 123
5+
logger:
6+
type: "file"
7+
format: "json"
8+
destination: "logs/{{ if .Step }}{{.Step.Name}}{{ else }}workflow{{ end }}.json"
9+
steps:
10+
- name: list
11+
logger:
12+
type: "stdout"
13+
command: ls -la
14+
metadata:
15+
cloud66.com/uuid: 8e2b4a31
16+
preflights:
17+
- command: true
18+
message: "Oh nose!"
19+
- name: env
20+
command: echo $USER
21+
- name: false
22+
command: false
23+
continue_on_fail: true
24+
- name: fail
25+
command: fail
26+
metadata:
27+
cloud66.com/uuid: 8e2b4a3e
28+
continue_on_fail: true
29+
- name: sleep
30+
command: sleep 30
31+
timeout: 1s
32+
metadata:
33+
cloud66.com/uuid: 547c8a3c
34+
continue_on_fail: true
35+
- name: trapper
36+
workdir: "$HOME/work/go/src/github.com/cloud66-oss/trackman/samples"
37+
command: ruby trapper.rb
38+
timeout: 1s
39+
continue_on_fail: true
40+
- name: piper
41+
workdir: "$HOME/work/go/src/github.com/cloud66-oss/trackman/samples"
42+
command: ruby piper.rb
43+
- name: dropcheck
44+
timeout: 3s
45+
workdir: "$HOME/work/go/src/github.com/cloud66-oss/trackman/samples"
46+
command: ruby filer.rb
47+
probe:
48+
command: ruby probe.rb
49+
continue_on_fail: true
50+
- name: arger
51+
metadata:
52+
cloud66.com/uuid: arger-123
53+
workdir: "$HOME/work/go/src/github.com/cloud66-oss/trackman/samples"
54+
command: "ruby arger.rb hello {{ index .MergedMetadata \"cloud66.com/test\" }}"

utils/context.go

-38
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,9 @@
11
package utils
22

3-
import (
4-
"context"
5-
6-
"github.com/sirupsen/logrus"
7-
)
8-
93
// CtxKey is a context key
104
type CtxKey struct{ int }
115

126
var (
137
// CtxSpinner is the key to a spinner on the context
148
CtxSpinner = CtxKey{1}
15-
// CtxLogger is the key to a logger on the context
16-
CtxLogger = CtxKey{2}
17-
// CtxLogLevel holds the desired log level on the context
18-
CtxLogLevel = CtxKey{3}
199
)
20-
21-
// GetLogger returns a new or existing logger from the context
22-
func getLogger(ctx context.Context) *logrus.Logger {
23-
var logger *logrus.Logger
24-
var logLevel logrus.Level
25-
if ctx.Value(CtxLogLevel) == nil {
26-
logLevel = logrus.DebugLevel
27-
} else {
28-
logLevel = ctx.Value(CtxLogLevel).(logrus.Level)
29-
}
30-
if ctx.Value(CtxLogger) == nil {
31-
logger = logrus.New()
32-
logger.SetLevel(logLevel)
33-
} else {
34-
logger = ctx.Value(CtxLogger).(*logrus.Logger)
35-
}
36-
37-
return logger
38-
}
39-
40-
// LoggerContext checks the context for a logger and creates a new one and puts it
41-
// on the context if not there
42-
func LoggerContext(ctx context.Context) (*logrus.Logger, context.Context) {
43-
logger := getLogger(ctx)
44-
ctx = context.WithValue(ctx, CtxLogger, logger)
45-
46-
return logger, ctx
47-
}

0 commit comments

Comments
 (0)