Skip to content

Commit

Permalink
Add an option to format logs with JSON (#378)
Browse files Browse the repository at this point in the history
* add an option to format logs with JSON

* added integration tests for log format

* clean up format options
  • Loading branch information
Massimiliano Pippi authored Aug 30, 2019
1 parent b035918 commit aef7461
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 8 deletions.
33 changes: 25 additions & 8 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"
"io/ioutil"
"os"
"strings"

"github.com/arduino/arduino-cli/cli/board"
"github.com/arduino/arduino-cli/cli/compile"
Expand Down Expand Up @@ -51,8 +52,9 @@ var (
PersistentPreRun: preRun,
}

verbose bool
logFile string
verbose bool
logFile string
logFormat string
)

const (
Expand Down Expand Up @@ -80,6 +82,7 @@ func createCliCommandTree(cmd *cobra.Command) {
cmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Print the logs on the standard output.")
cmd.PersistentFlags().StringVar(&globals.LogLevel, "log-level", defaultLogLevel, "Messages with this level and above will be logged (default: warn).")
cmd.PersistentFlags().StringVar(&logFile, "log-file", "", "Path to the file where logs will be written.")
cmd.PersistentFlags().StringVar(&logFormat, "log-format", "text", "The output format for the logs, can be [text|json].")
cmd.PersistentFlags().StringVar(&globals.OutputFormat, "format", "text", "The output format, can be [text|json].")
cmd.PersistentFlags().StringVar(&globals.YAMLConfigFile, "config-file", "", "The custom config file (if not specified the default will be used).")
cmd.PersistentFlags().StringSliceVar(&globals.AdditionalUrls, "additional-urls", []string{}, "Additional URLs for the board manager.")
Expand Down Expand Up @@ -111,6 +114,10 @@ func parseFormatString(arg string) (feedback.OutputFormat, bool) {
}

func preRun(cmd *cobra.Command, args []string) {
// normalize the format strings
globals.OutputFormat = strings.ToLower(globals.OutputFormat)
logFormat = strings.ToLower(logFormat)

// should we log to file?
if logFile != "" {
file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
Expand All @@ -120,7 +127,11 @@ func preRun(cmd *cobra.Command, args []string) {
}

// we use a hook so we don't get color codes in the log file
logrus.AddHook(lfshook.NewHook(file, &logrus.TextFormatter{}))
if logFormat == "json" {
logrus.AddHook(lfshook.NewHook(file, &logrus.JSONFormatter{}))
} else {
logrus.AddHook(lfshook.NewHook(file, &logrus.TextFormatter{}))
}
}

// should we log to stdout?
Expand All @@ -142,15 +153,21 @@ func preRun(cmd *cobra.Command, args []string) {
logrus.SetLevel(lvl)
}

// check the right format was passed
if f, found := parseFormatString(globals.OutputFormat); !found {
// set the Logger format
if logFormat == "json" {
logrus.SetFormatter(&logrus.JSONFormatter{})
}

// check the right output format was passed
format, found := parseFormatString(globals.OutputFormat)
if !found {
feedback.Error("Invalid output format: " + globals.OutputFormat)
os.Exit(errorcodes.ErrBadCall)
} else {
// use the format to configure the Feedback
feedback.SetFormat(f)
}

// use the output format to configure the Feedback
feedback.SetFormat(format)

globals.InitConfigs()

logrus.Info(globals.VersionInfo.Application + "-" + globals.VersionInfo.VersionString)
Expand Down
36 changes: 36 additions & 0 deletions test/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
# otherwise use the software for commercial activities involving the Arduino
# software without disclosing the source code of your own applications. To purchase
# a commercial license, send an email to license@arduino.cc.
import os
import json

import semver


Expand All @@ -36,3 +38,37 @@ def test_version(run_command):
assert parsed_out.get("Application", False) == "arduino-cli"
assert isinstance(semver.parse(parsed_out.get("VersionString", False)), dict)
assert isinstance(parsed_out.get("Commit", False), str)


def test_log_options(run_command, data_dir):
"""
using `version` as a test command
"""

# no logs
out_lines = run_command("version").stdout.strip().split("\n")
assert len(out_lines) == 1

# plain text logs on stdoud
out_lines = run_command("version -v").stdout.strip().split("\n")
assert len(out_lines) > 1
assert out_lines[0].startswith("\x1b[36mINFO\x1b[0m") # account for the colors

# plain text logs on file
log_file = os.path.join(data_dir, "log.txt")
run_command("version --log-file " + log_file)
with open(log_file) as f:
lines = f.readlines()
assert lines[0].startswith('time="') # file format is different from console

# json on stdout
out_lines = run_command("version -v --log-format JSON").stdout.strip().split("\n")
lg = json.loads(out_lines[0])
assert "level" in lg

# json on file
log_file = os.path.join(data_dir, "log.json")
run_command("version --log-format json --log-file " + log_file)
with open(log_file) as f:
for line in f.readlines():
json.loads(line)

0 comments on commit aef7461

Please sign in to comment.