Skip to content

senzing-garage/go-logging

Repository files navigation

go-logging

If you are beginning your journey with Senzing, please start with Senzing Quick Start guides.

You are in the Senzing Garage where projects are "tinkered" on. Although this GitHub repository may help you understand an approach to using Senzing, it's not considered to be "production ready" and is not considered to be part of the Senzing product. Heck, it may not even be appropriate for your application of Senzing!

Synopsis

The go-logging packages build a logging system upon Go's experimental slog package (https://pkg.go.dev/golang.org/x/exp/slog).

Go Reference Badge Go Report Card Badge License Badge go-test-linux.yaml Badge go-test-darwin.yaml Badge go-test-windows.yaml Badge

golangci-lint.yaml Badge

Overview

The Senzing go-logging packages use the message number to coordinate aspects of the log message such as message identification, message text, and logging level.

Logging levels

go-logging extends the levels of logging to include: TRACE, DEBUG, INFO, WARN, ERROR, FATAL, and PANIC.

The message number determines the log record level. The ranges are:

Level Range Use Comments
TRACE 0000-0999 Entry/Exit tracing May contain sensitive data.
DEBUG 1000-1999 Values seen during processing May contain sensitive data.
INFO 2000-2999 Process steps achieved
WARN 3000-3999 Unexpected situations, but processing was successful
ERROR 4000-4999 Unexpected situations, processing was not successful
FATAL 5000-5999 The process needs to shutdown
PANIC 6000-6999 The underlying system is at issue
8000-8999 Reserved for observer messages

WARNING: TRACE and DEBUG are meant for problem determination and should not be used in normal processing as the log records, by convention, may contain sensitive data.

Guards

go-logging supports "guards", e.g. IsXxxxx() methods, to avoid calling a Log() method that wouldn't print anyway because of the logging level. For instance, there's no reason to call a DEBUG Log() method when the logging level is set to INFO. Guards prevent this. Example:

 if logger.IsDebug() {
  logger.Log(1001, complexProcess())
 }

Use

The basic use of senzing/go-logging looks like this:

 import "github.com/senzing-garage/go-logging/logging"

 logger, _ := logging.New()
 logger.Log(2001, "Hello world!")

Output:

{"time":"YYYY-MM-DDThh:mm:ss.nnnnnnnnn-00:00","level":"INFO","id":"2001","details":{"1":"Hello World!"}}

Message format

Although not all fields may be present for an individual message, a complete message has these fields:

{
    "time": "YYYY-MM-DDThh:mm:ss.nnnnnnnnn-00:00",
    "level": "INFO",
    "text": "Sent SQL in /var/tmp/tmpfile.sql to database sqlite3://na:xxxxx@/tmp/sqlite/G2C.db",
    "id": "senzing-65032002",
    "status":  "status_message",
    "duration":  "",
    "location": "In processDatabase() at senzingschema.go:129",
    "errors": ["unknown value in foo",  "bar has no value"],
    "details": {
        "1": "/var/tmp/tmpfile.sql",
        "2": "sqlite3://na:xxxxx@/tmp/sqlite/G2C.db"
    }
}

Logging output

By default, logging goes to STDERR. Since go-logging is built upon the log package, this can be modified using log.SetOutput().

Examples:

  1. To have the output go a file, it would be something like this:

    import (
        "log"
        "os"
        "io"
    )
    
    aFile, err := os.Open("/path/to/a/logfile")
    log.SetOutput(io.Writer(aFile))
  2. To have the output go to STDERR and a file, it would be something like this:

    import (
        "log"
        "os"
        "io"
    )
    
    aFile, err := os.Open("/path/to/a/logfile")
    log.SetOutput(io.MultiWriter(os.Stderr, aFile))

Use with senzing-tools

In the suite of senzing-tools, logging is created by:

import (
    "fmt"
    "github.com/senzing-garage/go-logging/logging"
)

var (
    ComponentId = 9999            // See https://github.com/senzing-garage/knowledge-base/blob/main/lists/senzing-component-ids.md
    IdMessages  = map[int]string{ // Message templates. Example: https://github.com/senzing-garage/init-database/blob/main/senzingconfig/main.go
        2000: "Today's greeting:  %s",
        4000: "Here's what happened: %s",
    }
    callerSkip = 3                // Used to determine "location" information. See https://pkg.go.dev/runtime#Caller
)

// Logging options. See https://github.com/senzing-garage/go-logging/blob/main/logging/main.go
loggerOptions := []interface{}{
    logging.OptionCallerSkip{Value: callerSkip},
}

// Create a logger from a factory.
logger, err := logging.NewSenzingLogger(ComponentId, IdMessages, loggerOptions...)
if err != nil {
    fmt.Println(err)
}

// Write log record.
logger.Log(2000, "Hello, world!")

// Create an error
err = logger.NewError(4000, "A bad thing")
fmt.Printf("The error: %v\n", err)

Example output:

{"time":"YYYY-MM-DDThh:mm:ss.nnZ","level":"INFO","text":"Today's greeting:  Hello, world!","id":"senzing-99992000","location":"In main() at main.go:137","details":{"1":"Hello, world!"}}
The error: {"time":"YYYY-MM-DDThh:mm:ss.nnZ","level":"ERROR","id":"senzing-99994000","text":"Here's what happened: A bad thing","location":"In main() at main.go:140","details":{"1":"A bad thing"}}

References

  1. API documentation
  2. Development
  3. Errors
  4. Examples
  5. Package reference