blog

package module
v3.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 10, 2025 License: MIT Imports: 8 Imported by: 0

README

Blog · Tests codecov Go Report Go Reference GitHub License

Blog is a simple async logger with file rotation and console logging.

This project is born from a personal need for a performant logger and a desire to deepen my understanding of Go. While it's primarily a personal endeavor, I welcome anyone who finds it useful for their own projects and am open to evolving it based on user feedback and needs.

Features

  • Standard Library Only
  • Thread-Safe
  • Customizable At Runtime
  • Log File Rotation

Getting Started

go get github.com/Data-Corruption/blog/v3

Basic Example:

import (
  "github.com/Data-Corruption/blog/v3"
)

func main() {
  // Init blog.
  //
  // Parameters:
  //   - DirPath: Path for log files. "." for current working directory or "" to disable file logging.
  //   - Level: Desired logging level for filtering messages.
  //   - IncludeLocation: When true, adds source file and line number to log messages (e.g., "main.go:42").
  //   - EnableConsole: When true, enables logging to the console in addition to files.
  //
  var err error
  if err = blog.Init("logs", blog.INFO, false, true); err != nil {
    log.Printf("Error initializing logger: %v", err)
  }

  // Log messages from anywhere in the program
  blog.Info("This is an info message.")

  // Log messages with formatting
  blog.Warnf("This is an warn message with a format string: %v", err)

  // Synchronously cleanup the logger with a timeout; 0 means block indefinitely.
  // This should be called at the end of the program.
  blog.Cleanup(0)

  // for all other functions see `blog.go`. For access to the raw logger, see the other internal packages.
}

FAQ

In this section, you'll find answers to common questions and troubleshooting tips for using our project effectively.

How to Handle Log File Rotation

Question: What happens when the log file reaches its maximum size, and how can I manage it?

Answer: Blog automatically handles log file rotation based on the size limit you set. Once the latest.log file exceeds the specified maximum size, it's renamed with the current date and time, and a new latest.log file is created. You can adjust the maximum file size using blog.SetMaxFileSizeBytes(size). This ensures your logs are manageable and prevents excessive file growth.

Changing Settings Dynamically

Question: Can I change the logger's settings at runtime, and how?

Answer: Yes, you can dynamically adjust various settings in the logger. Due to the async nature of the logger these settings may take a few ms to update. Here is a list of available methods to update settings:

  • SetLevel(level LogLevel)
  • SetConsole(enable bool)
  • SetMaxBufferSizeBytes(size int) Larger values will increase memory usage and reduce the frequency of disk writes.
  • SetMaxFileSizeBytes(size int)
  • SetDirectoryPath(path string) "." for current directory and "" to disable file logging.
  • SetFlushInterval(d time.Duration) To disable automatic flushing, set to 0
Configuring Buffer and Flush Settings

Question: How can I optimize performance by configuring the internal buffer and flush intervals?

Answer: Blog optimizes log writing using a rolling buffer, which automatically flushes based on two configurable events:

  • Buffer Size Limit Reached: When the buffer accumulates to a certain size, it triggers a flush. You can set this threshold with blog.SetMaxBufferSizeBytes(size). The default size is 4KB. Larger values will reduce the frequency of disk writes but also increase memory usage.
  • Time Interval Elapsed: The buffer also flushes periodically after a specified time interval, ensuring logs are written even during low activity. Set this interval with blog.SetFlushInterval(amountOfTime). The default interval is 5 seconds. Shortening this time ensures more frequent writes, while lengthening it can reduce disk I/O. To disable entirely set this to 0.
Using Blog in Concurrent Environments

Question: Is Blog suitable for concurrent environments, and are there any special considerations for synchronous operations?

Answer: Blog is inherently safe for concurrent use in applications. Keep in mind it is asynchronous. Tf you require synchronous logging, I recommend checking out one of GO's many libs that support sync operation, like zap.

Logging Issue: Message not appearing in the log file

Question: After logging a message, flushing, and then reading the log file, why doesn't it contain my message?

Answer: This is likely due to the asynchronous nature of our logging system. These processes may require some time to execute. To resolve this:

  • Step 1: Wait for a few milliseconds after logging your message before flushing or cleanup.
  • Step 2: Similarly, wait for a few milliseconds after flushing before you attempt to read the log file.

Contributing

Contributions, issues, and feature requests are welcome! Feel free to check CONTRIBUTING.md for guidelines on how to contribute.

License

Distributed under the MIT License. See LICENSE.md for more information.

Documentation

Overview

Package blog is a simple async logger with file rotation and console logging.

Usage:

// Init blog.
//
// Parameters:
//   - DirPath: Path for log files. "." for current working directory or "" to disable file logging.
//   - Level: Desired logging level for filtering messages.
//   - IncludeLocation: When true, adds source file and line number to log messages (e.g., "main.go:42").
//   - EnableConsole: When true, enables logging to the console in addition to file.
//
if err := blog.Init("logs", blog.INFO, false, true); err != nil {
	log.Printf("Error initializing logger: %v", err)
}

// Log messages from anywhere in the program
blog.Info("This is an info message.")

// Log messages with formatting
blog.Warnf("This is an warn message with a format string: %v", err)

// Synchronously cleanup the logger with a timeout; 0 means block indefinitely.
// This should be called at the end of the program.
blog.Cleanup(0)

// for all other functions see `blog.go`. For access to the raw logger, see the other internal packages.

Performance Notes

Defaults; All of these are modifiable at runtime via the public functions:

  • Max buffer size: 4 KB.
  • Max log file size: 1 GB. When this is reached the file is rotated.
  • Flush interval: 15 seconds. For automatic flushing in low traffic scenarios.

A single thread is used to handle all logging operations. The channel that feeds it messages is buffered to 255 in the instance managed by the public functions. If you need control over it, you can create your own instance of the raw logger. Note interfacing with the raw logger is is different from the simplified public functions.

For contributors

The approach is pretty straightforward. There is a slightly lower abstraction level logger in the logger package. This file creates and manages an instance of it for the common use case of a high abstraction singleton logger.

The logger is a struct with a few channels for communication and vars for configuration. When created it starts a goroutine that listens for messages/config updates via the chans then handles them. The logger's public functions don't interact with it's state directly, they do so through the channels. This makes it thread-safe and more performant, as relying on go's event system is better than mutexes in this case.

This has some nice benefits:

  • Easily test multiple logger instances in parallel.
  • Users don't need to manage the logger instance themselves.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrAlreadyInitialized = fmt.Errorf("blog: already initialized")
	ErrInvalidLogLevel    = fmt.Errorf("blog: invalid log level")
	ErrUninitialized      = fmt.Errorf("blog: uninitialized")
	ErrShutdown           = fmt.Errorf("blog: logger has been shut down")
	ErrInvalidPath        = fmt.Errorf("blog: invalid path")
)

Functions

func Cleanup

func Cleanup(timeout time.Duration) error

Cleanup flushes the log write buffer and exits the logger. If timeout is 0, Cleanup blocks indefinitely.

func Debug

func Debug(msg string) error

func Debugf

func Debugf(format string, args ...any) error

func Error

func Error(msg string) error

func Errorf

func Errorf(format string, args ...any) error

func Fatal

func Fatal(exitCode int, timeout time.Duration, msg string) error

Fatal logs a fatal message and exits with the given exit code. This function will not return, it will exit the program after attempting to log the message.

func Fatalf

func Fatalf(exitCode int, timeout time.Duration, format string, args ...any) error

Fatalf logs a fatal message with a format string and exits with the given exit code. This function will not return, it will exit the program after attempting to log the message.

func Flush

func Flush() error

Flush manually flushes the log write buffer.

func Info

func Info(msg string) error

func Infof

func Infof(format string, args ...any) error

func Init

func Init(
	DirPath string,
	Level Level,
	IncludeLocation bool,
	EnableConsole bool,
) error

Init sets up the logger with the specified configuration parameters.

Parameters:

  • DirPath: Directory path for log files. Use "." for current working directory or "" to disable file logging.
  • Level: Desired logging level for filtering messages.
  • IncludeLocation: When true, adds source file and line number to log messages (e.g., "main.go:42").
  • EnableConsole: When true, enables logging to the console in addition to files.

Returns:

  • ErrAlreadyInitialized if logger was previously initialized,
  • ErrInvalidPath if the directory path is invalid for any reason,

func SetConsole

func SetConsole(enable bool) error

SetConsole enables or disables console logging.

func SetDirectoryPath

func SetDirectoryPath(path string) error

SetDirectoryPath sets the directory path for the log files. To disable file logging, use an empty string.

func SetFlushInterval

func SetFlushInterval(d time.Duration) error

SetFlushInterval sets the interval at which the log write buffer is automatically flushed to the log file. This happens regardless of the buffer size. A value of 0 disables automatic flushing.

func SetLevel

func SetLevel(level Level) error

SetLevel sets the log level.

func SetMaxBufferSizeBytes

func SetMaxBufferSizeBytes(size int) error

SetMaxBufferSizeBytes sets the maximum size of the log write buffer. Larger values will increase memory usage and reduce the frequency of disk writes.

func SetMaxFileSizeBytes

func SetMaxFileSizeBytes(size int) error

SetMaxFileSizeBytes sets the maximum size of the log file. When the log file reaches this size, it is renamed to the current timestamp and a new log file is created.

func SyncFlush

func SyncFlush(timeout time.Duration) error

SyncFlush synchronously flushes the log write buffer and blocks until the flush is complete or the timeout is reached. If timeout is 0, SyncFlush blocks indefinitely.

func Warn

func Warn(msg string) error

func Warnf

func Warnf(format string, args ...any) error

Types

type Level

type Level int
const (
	NONE Level = iota
	ERROR
	WARN
	INFO
	DEBUG
	FATAL
)

func (*Level) FromString

func (l *Level) FromString(levelStr string) error

FromString sets a blog.Level from a case-insensitive string, returning ErrInvalidLogLevel if the string is invalid.

func (Level) String

func (l Level) String() string

String returns the string representation of a blog.Level

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL