diff --git a/examples.txt b/examples.txt index de7120784..b637704b8 100644 --- a/examples.txt +++ b/examples.txt @@ -71,6 +71,7 @@ Command-Line Arguments Command-Line Flags Command-Line Subcommands Environment Variables +Logging HTTP Client HTTP Server Context diff --git a/examples/logging/logging.go b/examples/logging/logging.go new file mode 100644 index 000000000..18bbaf76d --- /dev/null +++ b/examples/logging/logging.go @@ -0,0 +1,77 @@ +// The Go standard library provides straightforward +// tools for outputting logs from Go programs, with +// the [log](https://pkg.go.dev/log) package for +// free-form output and the +// [log/slog](https://pkg.go.dev/log/slog) package for +// structured output. +package main + +import ( + "bytes" + "fmt" + "log" + "os" + + "log/slog" +) + +func main() { + + // Simply invoking functions like `Println` from the + // `log` package uses the _standard_ logger, which + // is already pre-configured for reasonable logging + // output to `os.Stderr`. Additional methods like + // `Fatal*` or `Panic*` will exit the program after + // logging. + log.Println("standard logger") + + // Loggers can be configured with _flags_ to set + // their output format. By default, the standard + // logger has the `log.Ldate` and `log.Ltime` flags + // set, and these are collected in `log.LstdFlags`. + // We can change its flags to emit time with + // microsecond accuracy, for example. + log.SetFlags(log.LstdFlags | log.Lmicroseconds) + log.Println("with micro") + + // It also supports emitting the file name and + // line from which the `log` function is called. + log.SetFlags(log.LstdFlags | log.Lshortfile) + log.Println("with file/line") + + // It may be useful to create a custom logger and + // pass it around. When creating a new logger, we + // can set a _prefix_ to distinguish its output + // from other loggers. + mylog := log.New(os.Stdout, "my:", log.LstdFlags) + mylog.Println("from mylog") + + // We can set the prefix + // on existing loggers (including the standard one) + // with the `SetPrefix` method. + mylog.SetPrefix("ohmy:") + mylog.Println("from mylog") + + // Loggers can have custom output targets; + // any `io.Writer` works. + var buf bytes.Buffer + buflog := log.New(&buf, "buf:", log.LstdFlags) + + // This call writes the log output into `buf`. + buflog.Println("hello") + + // This will actually show it on standard output. + fmt.Print("from buflog:", buf.String()) + + // The `slog` package provides + // _structured_ log output. For example, logging + // in JSON format is straightforward. + jsonHandler := slog.NewJSONHandler(os.Stderr, nil) + myslog := slog.New(jsonHandler) + myslog.Info("hi there") + + // In addition to the message, `slog` output can + // contain an arbitrary number of key=value + // pairs. + myslog.Info("hello again", "key", "val", "age", 25) +} diff --git a/examples/logging/logging.hash b/examples/logging/logging.hash new file mode 100644 index 000000000..4d1c7a70e --- /dev/null +++ b/examples/logging/logging.hash @@ -0,0 +1,2 @@ +38a7ef451859bb4c163df938b3a9d0e5ac293bef +Qd0uCqBlYUn diff --git a/examples/logging/logging.sh b/examples/logging/logging.sh new file mode 100644 index 000000000..00bcc76c1 --- /dev/null +++ b/examples/logging/logging.sh @@ -0,0 +1,18 @@ +# Sample output; the date and time +# emitted will depend on when the example ran. +$ go run logging.go +2023/08/22 10:45:16 standard logger +2023/08/22 10:45:16.904141 with micro +2023/08/22 10:45:16 logging.go:40: with file/line +my:2023/08/22 10:45:16 from mylog +ohmy:2023/08/22 10:45:16 from mylog +from buflog:buf:2023/08/22 10:45:16 hello + +# These are wrapped for clarity of presentation +# on the website; in reality they are emitted +# on a single line. +{"time":"2023-08-22T10:45:16.904166391-07:00", + "level":"INFO","msg":"hi there"} +{"time":"2023-08-22T10:45:16.904178985-07:00", + "level":"INFO","msg":"hello again", + "key":"val","age":25} diff --git a/public/environment-variables b/public/environment-variables index eb0ccb78d..ad03f4a1f 100644 --- a/public/environment-variables +++ b/public/environment-variables @@ -14,7 +14,7 @@ if (e.key == "ArrowRight") { - window.location.href = 'http-client'; + window.location.href = 'logging'; } } @@ -162,7 +162,7 @@ program picks that value up.

- Next example: HTTP Client. + Next example: Logging.

diff --git a/public/http-client b/public/http-client index b693af7c2..c00245320 100644 --- a/public/http-client +++ b/public/http-client @@ -9,7 +9,7 @@ onkeydown = (e) => { if (e.key == "ArrowLeft") { - window.location.href = 'environment-variables'; + window.location.href = 'logging'; } diff --git a/public/index.html b/public/index.html index 98549d651..54853fec8 100644 --- a/public/index.html +++ b/public/index.html @@ -173,6 +173,8 @@

Go by Example

  • Environment Variables
  • +
  • Logging
  • +
  • HTTP Client
  • HTTP Server
  • diff --git a/public/logging b/public/logging new file mode 100644 index 000000000..b945208e4 --- /dev/null +++ b/public/logging @@ -0,0 +1,276 @@ + + + + + Go by Example: Logging + + + + +
    +

    Go by Example: Logging

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    The Go standard library provides straightforward +tools for outputting logs from Go programs, with +the log package for +free-form output and the +log/slog package for +structured output.

    + +
    + +
    package main
    +
    + + + +
    import (
    +    "bytes"
    +    "fmt"
    +    "log"
    +    "os"
    +
    + + + +
        "log/slog"
    +)
    +
    + + + +
    func main() {
    +
    +

    Simply invoking functions like Println from the +log package uses the standard logger, which +is already pre-configured for reasonable logging +output to os.Stderr. Additional methods like +Fatal* or Panic* will exit the program after +logging.

    + +
    + +
        log.Println("standard logger")
    +
    +

    Loggers can be configured with flags to set +their output format. By default, the standard +logger has the log.Ldate and log.Ltime flags +set, and these are collected in log.LstdFlags. +We can change its flags to emit time with +microsecond accuracy, for example.

    + +
    + +
        log.SetFlags(log.LstdFlags | log.Lmicroseconds)
    +    log.Println("with micro")
    +
    +

    It also supports emitting the file name and +line from which the log function is called.

    + +
    + +
        log.SetFlags(log.LstdFlags | log.Lshortfile)
    +    log.Println("with file/line")
    +
    +

    It may be useful to create a custom logger and +pass it around. When creating a new logger, we +can set a prefix to distinguish its output +from other loggers.

    + +
    + +
        mylog := log.New(os.Stdout, "my:", log.LstdFlags)
    +    mylog.Println("from mylog")
    +
    +

    We can set the prefix +on existing loggers (including the standard one) +with the SetPrefix method.

    + +
    + +
        mylog.SetPrefix("ohmy:")
    +    mylog.Println("from mylog")
    +
    +

    Loggers can have custom output targets; +any io.Writer works.

    + +
    + +
        var buf bytes.Buffer
    +    buflog := log.New(&buf, "buf:", log.LstdFlags)
    +
    +

    This call writes the log output into buf.

    + +
    + +
        buflog.Println("hello")
    +
    +

    This will actually show it on standard output.

    + +
    + +
        fmt.Print("from buflog:", buf.String())
    +
    +

    The slog package provides +structured log output. For example, logging +in JSON format is straightforward.

    + +
    + +
        jsonHandler := slog.NewJSONHandler(os.Stderr, nil)
    +    myslog := slog.New(jsonHandler)
    +    myslog.Info("hi there")
    +
    +

    In addition to the message, slog output can +contain an arbitrary number of key=value +pairs.

    + +
    + +
        myslog.Info("hello again", "key", "val", "age", 25)
    +}
    +
    + + + + + + + + + + + + + +
    +

    Sample output; the date and time +emitted will depend on when the example ran.

    + +
    + +
    $ go run logging.go
    +2023/08/22 10:45:16 standard logger
    +2023/08/22 10:45:16.904141 with micro
    +2023/08/22 10:45:16 logging.go:40: with file/line
    +my:2023/08/22 10:45:16 from mylog
    +ohmy:2023/08/22 10:45:16 from mylog
    +from buflog:buf:2023/08/22 10:45:16 hello
    +
    +

    These are wrapped for clarity of presentation +on the website; in reality they are emitted +on a single line.

    + +
    + +
    {"time":"2023-08-22T10:45:16.904166391-07:00",
    + "level":"INFO","msg":"hi there"}
    +{"time":"2023-08-22T10:45:16.904178985-07:00",
    +    "level":"INFO","msg":"hello again",
    +    "key":"val","age":25}
    +
    + + +

    + Next example: HTTP Client. +

    + + + + +
    + + + +