From 76070234d4b451afe144c152188043573e3d9573 Mon Sep 17 00:00:00 2001 From: Arthur Barr Date: Wed, 6 Jan 2021 13:52:46 +0000 Subject: [PATCH] Optionally mirror web logs to stdout --- cmd/runmqserver/logging.go | 54 ++++++++++++++++++++---------- cmd/runmqserver/main.go | 12 ++++++- pkg/logger/logger.go | 14 ++++++-- test/docker/devconfig_test.go | 4 ++- test/docker/devconfig_test_util.go | 11 +++--- 5 files changed, 68 insertions(+), 27 deletions(-) diff --git a/cmd/runmqserver/logging.go b/cmd/runmqserver/logging.go index b21a5c5..3e196c9 100644 --- a/cmd/runmqserver/logging.go +++ b/cmd/runmqserver/logging.go @@ -1,5 +1,5 @@ /* -© Copyright IBM Corporation 2017, 2020 +© Copyright IBM Corporation 2017, 2021 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -79,6 +79,8 @@ func formatBasic(obj map[string]interface{}) string { if len(inserts) > 0 { return fmt.Sprintf("%s %s [%v]\n", obj["ibm_datetime"], obj["message"], strings.Join(inserts, ", ")) } + // Convert time zone information from some logs (e.g. Liberty) for consistency + obj["ibm_datetime"] = strings.Replace(obj["ibm_datetime"].(string), "+0000", "Z", 1) return fmt.Sprintf("%s %s\n", obj["ibm_datetime"], obj["message"]) } @@ -105,6 +107,11 @@ func mirrorHTPasswdLogs(ctx context.Context, wg *sync.WaitGroup, name string, fr return mirrorLog(ctx, wg, "/var/mqm/errors/mqhtpass.json", false, mf, true) } +// mirrorWebServerLogs starts a goroutine to mirror the contents of the Liberty web server messages.log +func mirrorWebServerLogs(ctx context.Context, wg *sync.WaitGroup, name string, fromStart bool, mf mirrorFunc) (chan error, error) { + return mirrorLog(ctx, wg, "/var/mqm/web/installations/Installation1/servers/mqweb/logs/messages.log", false, mf, true) +} + func getDebug() bool { debug := os.Getenv("DEBUG") if debug == "true" || debug == "1" { @@ -124,14 +131,21 @@ func configureLogger(name string) (mirrorFunc, error) { return nil, err } return func(msg string, isQMLog bool) bool { - obj, err := processLogMessage(msg) - if err == nil && isQMLog && filterQMLogMessage(obj) { - return false - } - if err != nil { - log.Printf("Failed to unmarshall JSON in log message - %v", msg) + // Check if the message is JSON + if len(msg) > 0 && msg[0] == '{' { + obj, err := processLogMessage(msg) + if err == nil && isQMLog && filterQMLogMessage(obj) { + return false + } + if err != nil { + log.Printf("Failed to unmarshall JSON in log message - %v", msg) + } else { + fmt.Println(msg) + } } else { - fmt.Println(msg) + // The log being mirrored isn't JSON, so wrap it in a simple JSON message + // MQ error logs are usually JSON, but this is useful for Liberty logs - usually expect WLP_LOGGING_MESSAGE_FORMAT=JSON to be set when mirroring Liberty logs. + fmt.Printf("{\"message\":\"%s\"}\n", msg) } return true }, nil @@ -141,16 +155,22 @@ func configureLogger(name string) (mirrorFunc, error) { return nil, err } return func(msg string, isQMLog bool) bool { - // Parse the JSON message, and print a simplified version - obj, err := processLogMessage(msg) - if err == nil && isQMLog && filterQMLogMessage(obj) { - return false - } - if err != nil { - log.Printf("Failed to unmarshall JSON in log message - %v", err) + // Check if the message is JSON + if len(msg) > 0 && msg[0] == '{' { + // Parse the JSON message, and print a simplified version + obj, err := processLogMessage(msg) + if err == nil && isQMLog && filterQMLogMessage(obj) { + return false + } + if err != nil { + log.Printf("Failed to unmarshall JSON in log message - %v", err) + } else { + fmt.Printf(formatBasic(obj)) + } } else { - fmt.Printf(formatBasic(obj)) - // fmt.Printf(formatSimple(obj["ibm_datetime"].(string), obj["message"].(string))) + // The log being mirrored isn't JSON, so just print it. + // MQ error logs are usually JSON, but this is useful for Liberty logs - usually expect WLP_LOGGING_MESSAGE_FORMAT=JSON to be set when mirroring Liberty logs. + fmt.Println(msg) } return true }, nil diff --git a/cmd/runmqserver/main.go b/cmd/runmqserver/main.go index 362a229..6210dc2 100644 --- a/cmd/runmqserver/main.go +++ b/cmd/runmqserver/main.go @@ -1,5 +1,5 @@ /* -© Copyright IBM Corporation 2017, 2020 +© Copyright IBM Corporation 2017, 2021 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -195,6 +195,16 @@ func doMain() error { return err } } + // Recommended to use this option in conjunction with setting WLP_LOGGING_MESSAGE_FORMAT=JSON + mirrorWebLog := os.Getenv("MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG") + if mirrorWebLog == "true" || mirrorWebLog == "1" { + _, err = mirrorWebServerLogs(ctx, &wg, name, newQM, mf) + if err != nil { + logTermination(err) + return err + } + } + err = updateCommandLevel() if err != nil { logTermination(err) diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 25a21c7..d9463ff 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -1,5 +1,5 @@ /* -© Copyright IBM Corporation 2018, 2019 +© Copyright IBM Corporation 2018, 2021 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -117,14 +117,22 @@ func (l *Logger) log(level string, msg string) { // Debug logs a line as debug func (l *Logger) Debug(args ...interface{}) { if l.debug { - l.log(debugLevel, fmt.Sprint(args...)) + if l.json { + l.log(debugLevel, fmt.Sprint(args...)) + } else { + l.log(debugLevel, "DEBUG: "+fmt.Sprint(args...)) + } } } // Debugf logs a line as debug using format specifiers func (l *Logger) Debugf(format string, args ...interface{}) { if l.debug { - l.log(debugLevel, fmt.Sprintf(format, args...)) + if l.json { + l.log(debugLevel, fmt.Sprintf(format, args...)) + } else { + l.log(debugLevel, fmt.Sprintf("DEBUG: "+format, args...)) + } } } diff --git a/test/docker/devconfig_test.go b/test/docker/devconfig_test.go index e8aa2a0..6634a71 100644 --- a/test/docker/devconfig_test.go +++ b/test/docker/devconfig_test.go @@ -1,7 +1,7 @@ // +build mqdev /* -© Copyright IBM Corporation 2018, 2019 +© Copyright IBM Corporation 2018, 2021 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -82,6 +82,8 @@ func TestDevSecure(t *testing.T) { "MQ_QMGR_NAME=" + qm, "MQ_APP_PASSWORD=" + appPassword, "DEBUG=1", + "WLP_LOGGING_MESSAGE_FORMAT=JSON", + "MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG=true", }, Image: imageName(), } diff --git a/test/docker/devconfig_test_util.go b/test/docker/devconfig_test_util.go index 6b13579..45d5a61 100644 --- a/test/docker/devconfig_test_util.go +++ b/test/docker/devconfig_test_util.go @@ -1,7 +1,7 @@ // +build mqdev /* -© Copyright IBM Corporation 2018, 2019 +© Copyright IBM Corporation 2018, 2021 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -48,8 +48,9 @@ var insecureTLSConfig *tls.Config = &tls.Config{ } func waitForWebReady(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config) { + t.Logf("%s Waiting for web server to be ready", time.Now().Format(time.RFC3339)) httpClient := http.Client{ - Timeout: time.Duration(3 * time.Second), + Timeout: time.Duration(10 * time.Second), Transport: &http.Transport{ TLSClientConfig: tlsConfig, }, @@ -63,13 +64,13 @@ func waitForWebReady(t *testing.T, cli *client.Client, ID string, tlsConfig *tls case <-time.After(1 * time.Second): req, err := http.NewRequest("GET", url, nil) req.SetBasicAuth("admin", defaultAdminPassword) - resp, err := httpClient.Do(req.WithContext(ctx)) + resp, err := httpClient.Do(req) if err == nil && resp.StatusCode == http.StatusOK { - t.Log("MQ web server is ready") + t.Logf("%s MQ web server is ready", time.Now().Format(time.RFC3339)) return } case <-ctx.Done(): - t.Fatal("Timed out waiting for web server to become ready") + t.Fatalf("%s Timed out waiting for web server to become ready", time.Now().Format(time.RFC3339)) } } }