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

Add support for json logging to file #4523

Merged
merged 1 commit into from
Jul 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.asciidoc
Expand Up @@ -60,6 +60,7 @@ https://github.com/elastic/beats/compare/v6.0.0-alpha2...master[Check the HEAD d
- New cli subcommands interface. {pull}4420[4420]
- Allow source path matching in `add_docker_metadata` processor. {pull}4495[4495]
- Add support for analyzers and multifields in fields.yml. {pull}4574[4574]
- Add support for JSON logging. {pull}4523[4523]

*Filebeat*

Expand Down
2 changes: 2 additions & 0 deletions auditbeat/auditbeat.reference.yml
Expand Up @@ -733,3 +733,5 @@ logging.files:
# Number of rotated log files to keep. Oldest files will be deleted first.
#keepfiles: 7

# Set to true to log messages in json format.
#logging.json: false
2 changes: 2 additions & 0 deletions filebeat/filebeat.reference.yml
Expand Up @@ -1115,3 +1115,5 @@ logging.files:
# Number of rotated log files to keep. Oldest files will be deleted first.
#keepfiles: 7

# Set to true to log messages in json format.
#logging.json: false
2 changes: 2 additions & 0 deletions heartbeat/heartbeat.reference.yml
Expand Up @@ -888,3 +888,5 @@ logging.files:
# Number of rotated log files to keep. Oldest files will be deleted first.
#keepfiles: 7

# Set to true to log messages in json format.
#logging.json: false
2 changes: 2 additions & 0 deletions libbeat/_meta/config.reference.yml
Expand Up @@ -674,3 +674,5 @@ logging.files:
# Number of rotated log files to keep. Oldest files will be deleted first.
#keepfiles: 7

# Set to true to log messages in json format.
#logging.json: false
54 changes: 43 additions & 11 deletions libbeat/logp/log.go
@@ -1,10 +1,12 @@
package logp

import (
"encoding/json"
"fmt"
"log"
"os"
"runtime/debug"
"strings"
"time"
)

Expand All @@ -30,6 +32,7 @@ type logger struct {
level Priority
selectors map[string]struct{}
debugAllSelectors bool
JSON bool

logger *log.Logger
syslog [LOG_DEBUG + 1]*log.Logger
Expand Down Expand Up @@ -73,21 +76,50 @@ func parseSelectors(selectors []string) (map[string]struct{}, bool) {

func debugMessage(calldepth int, selector, format string, v ...interface{}) {
if _log.level >= LOG_DEBUG && IsDebug(selector) {
send(calldepth+1, LOG_DEBUG, "DBG ", format, v...)
send(calldepth+1, LOG_DEBUG, "DBG", format, v...)
}
}

func send(calldepth int, level Priority, prefix string, format string, v ...interface{}) {

message := fmt.Sprintf(format, v...)
timestamp := time.Now().Format(time.RFC3339)
var bytes []byte
if _log.JSON {
log := map[string]interface{}{
"timestamp": timestamp,
"level": prefix,
"message": message,
}
bytes, _ = json.Marshal(log)
} else {
// Creates the log message and formats it
bytes = []byte(fmt.Sprintf("%s %s %s", timestamp, prefix, message))
}

if _log.toSyslog {
_log.syslog[level].Output(calldepth, fmt.Sprintf(format, v...))
if _log.JSON {
_log.syslog[level].Output(calldepth, string(bytes))
} else {
_log.syslog[level].Output(calldepth, string(message))
}
}
if _log.toStderr {
_log.logger.Output(calldepth, fmt.Sprintf(prefix+format, v...))
if _log.JSON {
_log.logger.Output(calldepth, string(bytes))
} else {
_log.logger.Output(calldepth, fmt.Sprintf("%s %s", prefix, message))
}
}
if _log.toFile {
// Creates a timestamp for the file log message and formats it
prefix = time.Now().Format(time.RFC3339) + " " + prefix
_log.rotator.WriteLine([]byte(fmt.Sprintf(prefix+format, v...)))
if _log.JSON {
_log.rotator.WriteLine(bytes)
} else {
// Makes sure all prefixes have the same length
prefix = prefix + strings.Repeat(" ", 4-len(prefix))
bytes = []byte(fmt.Sprintf("%s %s %s", timestamp, prefix, message))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if the Sprintf, which is basically a Join, could be implemented more efficient. A benchmark between this and the strings.Join version would be interesting.

If it can be optimized, it's probably worth it so that we don't affect the performance in the debug logging case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@urso probably knows from the top of his head? :-D

_log.rotator.WriteLine(bytes)
}
}
}

Expand Down Expand Up @@ -117,19 +149,19 @@ func msg(level Priority, prefix string, format string, v ...interface{}) {
}

func Info(format string, v ...interface{}) {
msg(LOG_INFO, "INFO ", format, v...)
msg(LOG_INFO, "INFO", format, v...)
}

func Warn(format string, v ...interface{}) {
msg(LOG_WARNING, "WARN ", format, v...)
msg(LOG_WARNING, "WARN", format, v...)
}

func Err(format string, v ...interface{}) {
msg(LOG_ERR, "ERR ", format, v...)
msg(LOG_ERR, "ERR", format, v...)
}

func Critical(format string, v ...interface{}) {
msg(LOG_CRIT, "CRIT ", format, v...)
msg(LOG_CRIT, "CRIT", format, v...)
}

// Deprecate logs a deprecation message.
Expand All @@ -152,7 +184,7 @@ func Beta(format string, v ...interface{}) {
// WTF prints the message at CRIT level and panics immediately with the same
// message
func WTF(format string, v ...interface{}) {
msg(LOG_CRIT, "CRIT ", format, v)
msg(LOG_CRIT, "CRIT", format, v)
panic(fmt.Sprintf(format, v...))
}

Expand Down
6 changes: 4 additions & 2 deletions libbeat/logp/logp.go
Expand Up @@ -27,6 +27,7 @@ type Logging struct {
Files *FileRotator
ToSyslog *bool `config:"to_syslog"`
ToFiles *bool `config:"to_files"`
JSON bool `config:"json"`
Level string
Metrics LoggingMetricsConfig `config:"metrics"`
}
Expand All @@ -47,7 +48,6 @@ func init() {
verbose = flag.Bool("v", false, "Log at INFO level")
toStderr = flag.Bool("e", false, "Log to stderr and disable syslog/file output")
debugSelectorsStr = flag.String("d", "", "Enable certain debug selectors")

}

func HandleFlags(name string) error {
Expand Down Expand Up @@ -80,7 +80,9 @@ func HandleFlags(name string) error {
// line flag with a later SetStderr call.
func Init(name string, config *Logging) error {
// reset settings from HandleFlags
_log = logger{}
_log = logger{
JSON: config.JSON,
}

logLevel, err := getLogLevel(config)
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions metricbeat/metricbeat.reference.yml
Expand Up @@ -1112,3 +1112,5 @@ logging.files:
# Number of rotated log files to keep. Oldest files will be deleted first.
#keepfiles: 7

# Set to true to log messages in json format.
#logging.json: false
2 changes: 2 additions & 0 deletions packetbeat/packetbeat.reference.yml
Expand Up @@ -1129,3 +1129,5 @@ logging.files:
# Number of rotated log files to keep. Oldest files will be deleted first.
#keepfiles: 7

# Set to true to log messages in json format.
#logging.json: false
2 changes: 2 additions & 0 deletions winlogbeat/winlogbeat.reference.yml
Expand Up @@ -703,3 +703,5 @@ logging.files:
# Number of rotated log files to keep. Oldest files will be deleted first.
#keepfiles: 7

# Set to true to log messages in json format.
#logging.json: false