Golang Log
Overview
Golang provides an inbuilt logging package, package log. The package log defines Logger, a type, along with the methods for formatting the output. The predefined Logger which is ‘standard’ can be accessed through the helper functions, , for instance,, Print[f|ln], Fatal[f|ln], and Panic[f|ln], which are fairly easy to use as compared to that of the logger which is manual. The logger writes to the error which is standard and then prints the date and time of each of the messages that are loggeEveryery log message can be seen on the output on a separate line even if the message that is been printed does not end in a new line since the logger with add a new line itself.
Introduction
Logging might seem to be a very simple task when seen from above that requires only a message to be written on the surface or display the message to a console also known as cmd or a file which is mostly a text file. When the best practices of the log are considered, then the level of logs, it's structuring, logging it to the different locations as well as displaying the right content of the log at the output is necessary. When all of these details are taken into consideration, logging becomes a complex task.
The main use of structured logging is for proper formatting of the log entries which can be processed quickly and is mostly a JSON object, allowing us to filter the entries in different ways depending on the condition. For instance, we can search for specific user IDs, names, or messages to filter out entries and display only relevant information that contains these keywords. When the logs are structured, it will be simple if we want to derive relevant metrics or information.
What to Log
Logging is very crucial when it comes to development and testing. It is used by every developer when the development process is in production and operations for the following reasons:
- Find bugs in the code of the application
- Find the issue related to the performance of the application
- Doing post-mortem analysis of security incidents or network outage
The data that is to be logged depends primarily on the application’s type. While logging there might be some variations in the following conditions:
- The timestamp of the log generated or when the event occurred.
- The levels of logs like error, info, and debug.
- Using conceptual data to help understand what exactly happens and how to resolve the issue.
What Not to Log
While logging, any form of sensitive data related to business or personal information shouldn’t be logged. These are not just limited to a set of information for here are some of the examples to make you understand what type of information to not log:
- Credit card name and number
- IP address and password
- Names or private identity
The restriction to this makes the log less useful in terms of engineering and testing purposes however, they are used for making the application secure and thus used by developers widely. In most cases, `GDPR and HIPAA regulations can help log personal information in the console.
Log Package
In Go’s standard library, there is a built-in log package that is used for providing the basic features for logging. It does not have log levels like error, warning, or debug but it has everything basic for logging and its setup. To understand this better, let's take a basic logging example
OUTPUT
Explanation: In this example, the code prints the log Hello developers! This is how you log along with the time 2009/11/10 23:00:00 at the output which is useful for filtering out the log messages by using the filtering parameter as a date.
Note: by default, the log package is used for printing the standard output stream for printing but we can also write it to the local file by using the io.Writer interface and also adding the timestamp to the log message without having to configure it additionally.
Logging to a File
If a golang log message is to be stored in a file, then it can be done by either creating a new file or opening an existing file and then setting it as the log output. To understand this better, let's take an example
Output:
Explanation: When the above code is executed, the following text is written in the Logs.txt file as an output.
As we discussed earlier that for outputting the log to any location be it a file, it can be done by implementing the interface io. The writer to get the flexibility of logging the message anywhere in the application.
Creating custom loggers
Even though there is a golang log package that provides and implements a predefined logger that is used for writing to standard error, we can also create a custom logger of different types by using the method log. New(). While creating a new logger, the following three arguments need to be passed as an argument to the method, log. New().
- out: this type implements the io. Writer interface where the log data will be written to the output.
- prefix: it is a string that is appended to the start of each line of the log.
- flag: it is a set of constants that is used for defining which properties of logging should be included in each entry of the log that is generated by the logger.
By taking advantage of this logging feature, we can create a custom logger. This can be better understood from the example given below.
Output:
Explanation: When the log.txt file is created just before the init function, three different loggers can be initialized and can be defined by providing the destination of the output in the argument, prefix string as well as log files. In the main function, the loggers can be used by using the function println which is used for writing the new log entry in the log file. When the code is executed, the following information will be written in the file Logs.txt
Note: the example that we used is writing into a single file however, a separate file can be used in each logger by passing a different file name in the argument when the logger is created.
Log Flags
The log flag constants can be used for enhancing the log messages by providing additional information like the number of lines, file name, date and time, etc. to understand how to use Log flags, look at the example given below
When the above code snippet is executed, the following output is printed:
However, the order in which this information is printed might differ, or even the format.
Introducing Logging Frameworks
The use of a package Log is very useful for local development, but generating a structured log is very important when we want to get feedback quickly. If getting feedback quickly is not important then using a logging framework isn’t necessary. The main reason for using the logging framework is that it helps us to standardize the data of the log. The following are the use cases of the logging framework:
- It makes it easier to read and understand the log data
- It also makes it easier to collect the log data from different sources and send it to a single platform to analyze it.
Choosing a Logging Framework
The main challenge is deciding which framework should be used from the options present. However, the two frameworks which are widely used are zap and log runs. The zap is the most popular and hence most used framework for logging. The logrus is, however, well maintained and updated and hence used widely in projects like Docker.
Getting Started With Zap Logger
The Zap is the package used for logging and is developed by developers from uber. This package is used for resolving all the issues that the default log package of Go had.
It is the fastest logging package in Go and provides a flexible and efficient way of logging messages in the application.
For installation, use the command given below:
Use Zap Logger as a Global
There are instances where instead of creating a logger and passing it to the function, it is efficient as well as convenient to use a global logger instead. The standard library of logs allows us to create both the custom log which is done by using the log. New() method or we can also use the instance of the standard logger directly by calling the helper function of the package like log. Printf(), etc. The zap provides functionalities like this by allowing us to use the methods like zap. L() and zap.S(), etc.
The global standard logger can be used by using the method zap. L(). This function is used for returning the instance of a shared logger. The sugared version of the same can be accessed via the method zap.S(). The main purpose or reason for using this method is that it provides a simple way of retrieving instances from anywhere in the code. If the standard logger is to be used then it has to replace the core logger with that of a different logger by using the method zap.ReplaceGlobals(). To understand this better, look at the example given below:
Output:
Different Logging Level - Development, Production, Error
The log event appears to be in every application and logging library. We are aware of basic levels like debugging, warning, and error. Make sure you use the same logging levels in development as in production. The logging levels in golang are usually considered on basis of the importance, for instance, you can turn on “unimportant” levels in development like trace and debug and enable the most important levels like error or warning in production where in the time taken by resources are important for instance, CPU time and disk space.
Getting Started With Logrus
To install the logrus, execute the following command in your terminal:
The feature of logrus is that it is completely compatible with the package Log of the standard library and replacing the Log imports with log "github.com/sirupsen/logrus" will work properly. Let us understand this by using the example given below:
Output:
Explanation: In this example, we have modified the normal code with imports and have replaced it with the log "github.com/sirupsen/logrus" which works perfectly fine and the output is printed.
Logging in JSON
If you want to log in a JSON object then Logrus is the best option since it provides structured logging in JSON and is easy to integrate with other services, parse the log, and add context to log messages by using fields as shown in the code given below.
OUTPUT
Explanation: If you don't want to output your logs in JSON format then the third-party formatters can be used or you can even write your format.
Log levels
The logrus provides various log levels, unlike the standard package of the log. There are seven log levels in logrus which are as follows:
- Trace
- Debug
- Info
- Warn
- Error
- Fatal
- Panic
The severity of the levels of log increases as the list proceeds. To understand this concept, look at the example given below
OUTPUT
Explanation In this example, we can notice that the debug-level text is not printed. To include it in the log, we have to set the log. Level to equal log.DebugLevel by using the command given below
When the logger is set with the logging level, we can log the entries depending on the environment of the device. The logrus will execute anything that is info or above, for instance, Warn, Error, Fatal, or Panic.
Conclusion
- The golang log defines Logger, a type, along with the methods for formatting the output. The predefined Logger which is ‘standard’ can be accessed through the helper functions, for instance, Print[f|ln], Fatal[f|ln], and Panic[f|ln], which are fairly easy to use as compared to that of the logger which is manual. The logger writes to the error which is standard and then prints the date and time of each of the messages that are logged.
- Every log message can be seen on the output on a separate line even if the message that is been printed does not end in a new line, since the logger with add a new line itself.
- The main use of structured logging is for proper formatting of the log entries which can be processed quickly and is mostly a JSON object, allowing us to filter the entries in different ways depending on the condition. For instance, we can search for specific user IDs, names, or messages to filter out entries and display only relevant information that contains these keywords. When the logs are structured, it will be simple if we want to derive relevant metrics or information.
- When the best practices of the log are considered, then the level of logs, it's structuring, logging it to the different locations as well as displaying the right content of the log at the output is necessary. When all of these details are taken into consideration, logging becomes a complex task.