Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Latest commit

 

History

History
executable file
·
304 lines (229 loc) · 7.86 KB

03.2.md

File metadata and controls

executable file
·
304 lines (229 loc) · 7.86 KB

log package

log package is used for logging. The examples (unlike some other packages) are not very helpful. It's very bare bones and has only two logging levels.

For anything complicated use Google's glog package.

Basic logging

Basic logging is similar to other languages.

// 03.2-01-basic-logging.go
package main

import (
    "log"
)

func main() {

    a, b := 10, 20

    log.Print("Use Print to log.")
    log.Println("Ditto for Println.")
    log.Printf("Use Printf and format strings. %d + %d = %d", a, b, a+b)
}

Each log is on a new line:

$ go run 03.2-01-basic-logging.go
2017/12/25 22:18:38 Use Print to log.
2017/12/25 22:18:38 Ditto for Println.
2017/12/25 22:18:38 Use Printf and format strings. 10 + 20 = 30

We can also forward the output to a file (or any number of io.Writers) with [log.SetOutput][setoutput1-log-pkg].

logFile, err := os.Create("log1.txt")
if err != nil {
    panic("Could not open file")
}

log.SetOutput(logFile)

Custom logger

We can setup a custom logger with logger.New.

func New(out io.Writer, prefix string, flag int) *Logger
  • out: Log destination. Any io.Writer like files.
  • prefix: Appears before each log entry. Think Warning/Info/Error.
  • flag: Defines logging properties (e.g. the date time format).

Log to file

Using out we can log to files.

// 03.2-02-log-file.go
package main

import (
    "log"
    "os"
)

func main() {

    // Create a file
    logFile, err := os.Create("log1.txt")
    if err != nil {
        panic("Could not open file")
    }

    // Close the file after main returns
    defer logFile.Close()

    a, b := 10, 20

    // We will not use the other options
    myLog := log.New(logFile, "", 0)

    myLog.Print("Use Print to log.")
    myLog.Println("Ditto for Println.")
    myLog.Printf("Use Printf and format strings. %d + %d = %d", a, b, a+b)
}

log1.txt will contain:

Use Print to log.
Ditto for Println.
Use Printf and format strings. 10 + 20 = 30

After New, mylog.SetOutput(w io.Writer) can redirect the logger.

Logging to multiple files/streams

It's also possible to log to multiple files (or io.Writers) with io.MultiWriter. This is useful when we want to both output to stdout and to files.

// 03.2-03-log-multiple-files.go
package main

import (
    "bytes"
    "fmt"
    "io"
    "log"
    "os"
)

func main() {

    // Create a file
    logFile, err := os.Create("log1.txt")
    if err != nil {
        panic("Could not open file")
    }

    // Close the file after main returns
    defer logFile.Close()

    // Create a second file
    logFile2, err := os.Create("log2.txt")
    if err != nil {
        panic("Could not open file2")
    }

    defer logFile2.Close()

    // Create a buffer
    var buflog bytes.Buffer

    multiW := io.MultiWriter(logFile, logFile2, &buflog, os.Stdout)

    a, b := 10, 20

    // Log to multiW
    myLog := log.New(multiW, "", 0)

    myLog.Print("Use Print to log.")
    myLog.Println("Ditto for Println.")
    myLog.Printf("Use Printf and format strings. %d + %d = %d", a, b, a+b)

    // Print buffer
    fmt.Println("Buffer:")
    fmt.Println(buflog.String())
}

We can see what we logged in both stdout and buffer:

$ go run 03.2-03-log-multiple-files.go
Use Print to log.
Ditto for Println.
Use Printf and format strings. 10 + 20 = 30
Buffer:
Use Print to log.
Ditto for Println.
Use Printf and format strings. 10 + 20 = 30

Flag

Prefix should be next but by discussing flag we can see if it appears before flag format or not. flag is an integer and is a collection of bits (like FLAGS CPU register). The flags are defined as constants:

// https://godoc.org/log#pkg-constants

const (
    // Bits or'ed together to control what's printed.
    // There is no control over the order they appear (the order listed
    // here) or the format they present (as described in the comments).
    // The prefix is followed by a colon only when Llongfile or Lshortfile
    // is specified.
    // For example, flags Ldate | Ltime (or LstdFlags) produce,
    //  2009/01/23 01:23:23 message
    // while flags Ldate | Ltime | Lmicroseconds | Llongfile produce,
    //  2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
    Ldate         = 1 << iota     // the date in the local time zone: 2009/01/23
    Ltime                         // the time in the local time zone: 01:23:23
    Lmicroseconds                 // microsecond resolution: 01:23:23.123123.  assumes Ltime.
    Llongfile                     // full file name and line number: /a/b/c/d.go:23
    Lshortfile                    // final file name element and line number: d.go:23. overrides Llongfile
    LUTC                          // if Ldate or Ltime is set, use UTC rather than the local time zone
    LstdFlags     = Ldate | Ltime // initial values for the standard logger
)

There's only room for a few bits of customization (see what I did there?).

// 03.2-04-log-flags.go
package main

import (
    "log"
    "os"
)

func main() {

    a, b := 10, 20

    // New logger will output to stdout with flags
    // Only log date and file
    myLog := log.New(os.Stdout, "", log.Ldate|log.Lshortfile)

    myLog.Print("Use Print to log.")
    myLog.Println("Ditto for Println.")
    myLog.Printf("Use Printf and format strings. %d + %d = %d", a, b, a+b)
}

We log date and filename:

$ go run 03.2-04-log-flags.go
2017/12/26 03.2-04-log-flags.go:25: Use Print to log.
2017/12/26 03.2-04-log-flags.go:26: Ditto for Println.
2017/12/26 03.2-04-log-flags.go:27: Use Printf and format strings. 10 + 20 = 30

Prefix

prefix adds a string to the beginning of each log line.

// 03.2-05-log-prefix.go
package main

import (
    "log"
    "os"
)

func main() {

    a, b := 10, 20

    // New logger will output to stdout with prefix "Log1: " and flags
    // Note the space in prefix
    myLog := log.New(os.Stdout, "Log1: ", log.Ldate|log.Lshortfile)

    myLog.Print("Use Print to log.")
    myLog.Println("Ditto for Println.")
    myLog.Printf("Use Printf and format strings. %d + %d = %d", a, b, a+b)
}

Prefix is printed before flags:

$ go run 03.2-05-log-prefix.go
Log1: 2017/12/26 03.2-05-log-prefix.go:16: Use Print to log.
Log1: 2017/12/26 03.2-05-log-prefix.go:17: Ditto for Println.
Log1: 2017/12/26 03.2-05-log-prefix.go:18: Use Printf and format strings. 10 + 20 = 30

Logging levels

log only supports two logging levels:

  • Fatal: log.Print and calls os.Exit(1).
  • Panic: log.Print and calls panic().

Both of these support ln and f variants (e.g. Fatalf, Panicln).

Continue reading ⇒ 04 - Go networking