So far we've been logging in to stdout
, but you can utilize any io.Writer
to ingest the log data. In fact, you can use multiple io.Writers
if you want the output to be routed to more than one place.
Most mature applications will write to more than one log file to delineate between the various types of messages that need to be retained.
The most common use case for this is found in web server. They typically keep an access.log
and an error.log
file to allow the analysis of all successful requests; however, they also maintain separate logging of different types of messages.
In the following example, we modify our logging concept to include errors as well as warnings:
package main import ( "log" "os" ) var ( Warn *log.Logger Error *log.Logger Notice *log.Logger ) func main() { warnFile, err := os.OpenFile("warnings.log", os.O_RDWR|os.O_APPEND, 0660) defer warnFile.Close() if err != nil { log.Fatal(err) } errorFile, err := os.OpenFile("error.log", os.O_RDWR|os.O_APPEND, 0660) defer errorFile.Close() if err != nil { log.Fatal(err) } Warn = log.New(warnFile, "WARNING: ", Log.LstdFlags ) Warn.Println("Messages written to a file called 'warnings.log' are likely to be ignored :(") Error = log.New(errorFile, "ERROR: ", log.Ldate|log.Ltime) Error.SetOutput(errorFile) Error.Println("Error messages, on the other hand, tend to catch attention!") }
We can take this approach to store all sorts of information. For example, if we wanted to store registration errors, we can create a specific registration error logger and allow a similar approach if we encounter an error in that process as shown:
res, err := database.Exec("INSERT INTO users SET user_name=?, user_guid=?, user_email=?, user_password=?", name, guid, email, passwordEnc) if err != nil { fmt.Fprintln(w, err.Error) RegError.Println("Could not complete registration:", err.Error) } else { http.Redirect(w, r, "/page/"+pageGUID, 301) }
18.226.163.229