LogContext struct

LogContext represents a hierarchical logging context. Contexts can be

nested and will automatically generate a prefix based on their

parent/child relationship.

Fields:

  • Name (string)
  • Parent (*LogContext)

Methods:

Prefix

Prefix returns the context prefix in the form "parent:child". An empty

context results in an empty string.


Returns:
  • string

Show/Hide Method Body
{
	if c == nil {
		return ""
	}

	if c.Parent == nil {
		return c.Name
	}

	parent := c.Parent.Prefix()
	if parent == "" {
		return c.Name
	}

	if c.Name == "" {
		return parent
	}

	return parent + ":" + c.Name
}

NewLogContext function

NewLogContext creates a new LogContext optionally linked to a parent.

Parameters:

  • name string
  • parent *LogContext

Returns:

  • *LogContext
Show/Hide Function Body
{
	return &LogContext{Name: name, Parent: parent}
}

Logger struct

Logger represents a logger for the application.

Fields:

  • Term (log.Logger)
  • File (log.Logger)
  • mu (sync.Mutex)
  • ErrIndex (map[string]int)

Methods:

nextErrIndex


Parameters:
  • prefix string

Returns:
  • int

Show/Hide Method Body
{
	l.mu.Lock()
	defer l.mu.Unlock()

	if l.ErrIndex == nil {
		l.ErrIndex = make(map[string]int)
	}

	idx := l.ErrIndex[prefix]
	l.ErrIndex[prefix] = idx + 1
	return idx
}

InfoCtx

InfoCtx logs an informational message using the provided context.


Parameters:
  • ctx *LogContext
  • msg string

Show/Hide Method Body
{
	prefix := ctx.Prefix()
	formatted := fmt.Sprintf("%s:info:%s", prefix, msg)
	l.File.Info().Msg(formatted)
	l.Term.Info().Msg(formatted)
}

WarnCtx

WarnCtx logs a warning message using the provided context.


Parameters:
  • ctx *LogContext
  • msg string

Show/Hide Method Body
{
	prefix := ctx.Prefix()
	formatted := fmt.Sprintf("%s:warn:%s", prefix, msg)
	l.File.Warn().Msg(formatted)
	l.Term.Warn().Msg(formatted)
}

ErrorCtx

ErrorCtx logs an error message using the provided context. The error index

is automatically incremented per-context to provide consistent progression.


Parameters:
  • ctx *LogContext
  • msg string

Show/Hide Method Body
{
	prefix := ctx.Prefix()
	idx := l.nextErrIndex(prefix)
	formatted := fmt.Sprintf("%s:err(%d):%s", prefix, idx, msg)
	l.File.Error().Msg(formatted)
	l.Term.Error().Msg(formatted)
}

getLogPath function

getLogPath returns the path to the log directory, if the user is running as

root, the logs will be stored in /var/vlogs/, otherwise the logs will be

stored in ~/.vlogs.

Returns:

  • string
  • error
Show/Hide Function Body
{
	var logPath string

	if os.Geteuid() == 0 {
		logPath = "/var/vlogs/"
	} else {
		homeDir, err := os.UserHomeDir()
		if err != nil {
			return "", fmt.Errorf("failed to get user home directory: %v", err)
		}
		logPath = filepath.Join(homeDir, ".vlogs")
	}

	// we have to create the directory if it doesn't exist
	if _, err := os.Stat(logPath); os.IsNotExist(err) {
		err := os.MkdirAll(logPath, 0755)
		if err != nil {
			return "", fmt.Errorf("failed to create log directory: %v", err)
		}
	}

	return logPath, nil
}

NewLogger function

NewLogger creates a new logger for the application, each logger has

a file logger and a console logger. The file logger is used to log

to the vlogs directory, while the console logger is used to log to

the console.

Example:

logger, err := logs.NewLogger(app)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
logger.File.Info().Msg("Batman reached the file logger")
logger.Console.Info().Msg("Batman reached the console logger")

since we use structured logging, we can also log with fields:

logger.File.Info().Str("where", "file").Msg("Batman is saving Gotham")
logger.Console.Info().Str("where", "console").Msg("Batman is saving Gotham")

Parameters:

  • domain string

Returns:

  • Logger
  • error

References:

Show/Hide Function Body
{
	vLogger := Logger{}
	vLogger.ErrIndex = make(map[string]int)

	// preparing the file logger
	logPath, err := getLogPath()
	if err != nil {
		return vLogger, err
	}

	vLogFile := filepath.Join(logPath, domain, "log.json")

	vLogger.File = log.Logger{
		Level: log.ParseLevel("info"),
		Writer: &log.FileWriter{
			Filename:     vLogFile,
			FileMode:     0600,
			MaxSize:      500 * 1024 * 1024,
			MaxBackups:   7,
			EnsureFolder: true,
			LocalTime:    true,
			TimeFormat:   "15:04:05",
			Cleaner: func(filename string, maxBackups int, matches []os.FileInfo) {
				var dir = filepath.Dir(filename)
				for i, fi := range matches {
					filename := filepath.Join(dir, fi.Name())
					switch {
					case i > maxBackups:
						os.Remove(filename)
					case !strings.HasSuffix(filename, ".gz"):
						go exec.Command("nice", "gzip", filename).Run()
					}
				}
			},
		},
	}

	// setting up the rotation for the file logger
	runner := cron.New(cron.WithLocation(time.Local))
	runner.AddFunc("0 0 * * *", func() { vLogger.File.Writer.(*log.FileWriter).Rotate() })
	go runner.Run()

	// preparing the console logger
	vLogger.Term = log.Logger{
		TimeFormat: "15:04:05",
		Caller:     1,
		Writer: &log.ConsoleWriter{
			Formatter:      formatLog,
			EndWithMessage: true,
		},
	}

	return vLogger, nil
}

formatLog function

formatLog formats the log message with appropriate colors for log level

Parameters:

  • w io.Writer
  • a *log.FormatterArgs

Returns:

  • int
  • error
Show/Hide Function Body
{
	var color, three string

	// Determine color and abbreviation for log level
	switch a.Level {
	case "trace":
		color, three = Magenta, "TRC"
	case "debug":
		color, three = Yellow, "DBG"
	case "info":
		color, three = Green, "INF"
	case "warn":
		color, three = Red, "WRN"
	case "error":
		color, three = Red, "ERR"
	case "fatal":
		color, three = Red, "FTL"
	case "panic":
		color, three = Red, "PNC"
	default:
		color, three = Gray, "???"
	}

	// Format the log message
	formattedLog := fmt.Sprintf("%s%s%s ", color, three, Reset)
	formattedLog += fmt.Sprintf("%s>%s", Cyan, Reset)
	formattedLog += fmt.Sprintf(" %s\n", a.Message)

	return fmt.Fprint(w, formattedLog)
}

fmt import

Import example:

import "fmt"

sync import

Import example:

import "sync"

github.com/phuslu/log import

Import example:

import "github.com/phuslu/log"

fmt import

Import example:

import "fmt"

io import

Import example:

import "io"

os import

Import example:

import "os"

os/exec import

Import example:

import "os/exec"

path/filepath import

Import example:

import "path/filepath"

strings import

Import example:

import "strings"

time import

Import example:

import "time"

github.com/phuslu/log import

Import example:

import "github.com/phuslu/log"

github.com/robfig/cron/v3 import

Import example:

import "github.com/robfig/cron/v3"