Logger
The Go Pip SDK provides a comprehensive logging system with configurable levels, structured output, and specialized logging methods for pip operations.
Log Levels
LogLevel
type LogLevel int
const (
LogLevelDebug LogLevel = iota
LogLevelInfo
LogLevelWarn
LogLevelError
LogLevelFatal
)Enumeration of available log levels in order of severity.
Methods:
String
func (l LogLevel) String() stringReturns the string representation of the log level.
Example:
level := pip.LogLevelInfo
fmt.Println(level.String()) // Output: "INFO"Core Types
Logger
type Logger struct {
level LogLevel
output io.Writer
prefix string
flags int
enableFile bool
logFile *os.File
}The main logger implementation with structured logging capabilities.
LoggerConfig
type LoggerConfig struct {
Level LogLevel // Minimum log level to output
Output io.Writer // Output destination (default: os.Stdout)
Prefix string // Log prefix (default: "[pip-sdk]")
EnableFile bool // Enable file logging
LogFile string // Log file path (if EnableFile is true)
Flags int // Log flags (default: log.LstdFlags)
}Configuration for logger creation.
Constructor Functions
NewLogger
func NewLogger(config *LoggerConfig) (*Logger, error)Creates a new logger instance with the specified configuration.
Parameters:
config(*LoggerConfig): Logger configuration. Ifnil, default configuration is used.
Returns:
*Logger: New logger instance.error: Error if logger creation fails.
Example:
// Create with default configuration
logger, err := pip.NewLogger(nil)
if err != nil {
return err
}
defer logger.Close()
// Create with custom configuration
config := &pip.LoggerConfig{
Level: pip.LogLevelDebug,
Output: os.Stdout,
Prefix: "[my-app]",
EnableFile: true,
LogFile: "/var/log/pip-sdk.log",
}
logger, err := pip.NewLogger(config)
if err != nil {
return err
}
defer logger.Close()DefaultLoggerConfig
func DefaultLoggerConfig() *LoggerConfigReturns a default logger configuration with sensible defaults.
Returns:
*LoggerConfig: Default configuration.
Default Values:
&LoggerConfig{
Level: LogLevelInfo,
Output: os.Stdout,
Prefix: "[pip-sdk]",
EnableFile: false,
Flags: log.LstdFlags,
}Core Logging Methods
Debug
func (l *Logger) Debug(format string, args ...interface{})Logs a debug message. Only output if log level is Debug or lower.
Info
func (l *Logger) Info(format string, args ...interface{})Logs an informational message.
Warn
func (l *Logger) Warn(format string, args ...interface{})Logs a warning message.
Error
func (l *Logger) Error(format string, args ...interface{})Logs an error message.
Fatal
func (l *Logger) Fatal(format string, args ...interface{})Logs a fatal message and exits the program with status code 1.
Example:
logger.Debug("Debugging package installation: %s", pkg.Name)
logger.Info("Installing package: %s", pkg.Name)
logger.Warn("Package %s is deprecated", pkg.Name)
logger.Error("Failed to install package: %v", err)
// logger.Fatal("Critical error: %v", err) // This will exit the programSpecialized Logging Methods
LogCommand
func (l *Logger) LogCommand(command string, args []string, duration time.Duration)Logs command execution with timing information.
Parameters:
command(string): Command that was executed.args([]string): Command arguments.duration(time.Duration): Execution duration.
Example:
start := time.Now()
// Execute command...
duration := time.Since(start)
logger.LogCommand("pip", []string{"install", "requests"}, duration)
// Output: [INFO] Command executed: pip install requests (duration: 2.5s)LogCommandError
func (l *Logger) LogCommandError(command string, args []string, err error, output string)Logs command execution errors with detailed information.
Parameters:
command(string): Command that failed.args([]string): Command arguments.err(error): Error that occurred.output(string): Command output.
LogPackageOperation
func (l *Logger) LogPackageOperation(operation, packageName string, success bool, duration time.Duration)Logs package operations (install, uninstall, etc.) with timing.
Parameters:
operation(string): Operation type (e.g., "install", "uninstall").packageName(string): Name of the package.success(bool): Whether the operation succeeded.duration(time.Duration): Operation duration.
Example:
start := time.Now()
err := manager.InstallPackage(pkg)
duration := time.Since(start)
logger.LogPackageOperation("install", pkg.Name, err == nil, duration)LogVenvOperation
func (l *Logger) LogVenvOperation(operation, path string, success bool)Logs virtual environment operations.
Parameters:
operation(string): Operation type (e.g., "create", "activate", "remove").path(string): Virtual environment path.success(bool): Whether the operation succeeded.
LogProjectOperation
func (l *Logger) LogProjectOperation(operation, path string, success bool)Logs project operations.
Parameters:
operation(string): Operation type (e.g., "init", "build").path(string): Project path.success(bool): Whether the operation succeeded.
Configuration Methods
SetLevel
func (l *Logger) SetLevel(level LogLevel)Sets the minimum log level for output.
GetLevel
func (l *Logger) GetLevel() LogLevelReturns the current log level.
IsEnabled
func (l *Logger) IsEnabled(level LogLevel) boolChecks if a specific log level is enabled.
Example:
if logger.IsEnabled(pip.LogLevelDebug) {
// Expensive debug operation
debugInfo := generateDebugInfo()
logger.Debug("Debug info: %s", debugInfo)
}Close
func (l *Logger) Close() errorCloses the logger and any open log files.
Returns:
error: Error if closing fails.
Utility Functions
ParseLogLevel
func ParseLogLevel(level string) (LogLevel, error)Parses a log level string into a LogLevel constant.
Parameters:
level(string): Log level string (case-insensitive).
Returns:
LogLevel: Parsed log level.error: Error if parsing fails.
Supported Strings:
- "DEBUG"
- "INFO"
- "WARN", "WARNING"
- "ERROR"
- "FATAL"
Example:
level, err := pip.ParseLogLevel("DEBUG")
if err != nil {
return err
}
logger.SetLevel(level)Integration with Manager
The logger can be integrated with the pip manager for automatic operation logging.
SetCustomLogger
func (m *Manager) SetCustomLogger(logger *Logger)Sets a custom logger for the manager to use.
Example:
// Create custom logger
logger, err := pip.NewLogger(&pip.LoggerConfig{
Level: pip.LogLevelDebug,
EnableFile: true,
LogFile: "pip-operations.log",
})
if err != nil {
return err
}
// Set logger on manager
manager := pip.NewManager(nil)
manager.SetCustomLogger(logger)
// All operations will now be logged
manager.InstallPackage(&pip.PackageSpec{Name: "requests"})Log Output Format
The logger produces structured log entries with the following format:
YYYY-MM-DD HH:MM:SS.mmm [LEVEL] [prefix] filename:line - messageExample Output:
2024-01-15 14:30:25.123 [INFO] [pip-sdk] manager.go:45 - Installing package: requests
2024-01-15 14:30:27.456 [INFO] [pip-sdk] operations.go:123 - Command executed: pip install requests (duration: 2.3s)
2024-01-15 14:30:27.457 [INFO] [pip-sdk] operations.go:89 - Package install successful: requests (duration: 2.3s)Advanced Usage
Multiple Output Destinations
// Log to both file and stdout
file, err := os.OpenFile("pip.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
return err
}
multiWriter := io.MultiWriter(os.Stdout, file)
logger, err := pip.NewLogger(&pip.LoggerConfig{
Level: pip.LogLevelInfo,
Output: multiWriter,
})Structured Logging with JSON
type JSONLogger struct {
*pip.Logger
encoder *json.Encoder
}
func (jl *JSONLogger) Info(format string, args ...interface{}) {
entry := map[string]interface{}{
"timestamp": time.Now().Format(time.RFC3339),
"level": "INFO",
"message": fmt.Sprintf(format, args...),
}
jl.encoder.Encode(entry)
}Conditional Logging
func logIfVerbose(logger *pip.Logger, verbose bool, format string, args ...interface{}) {
if verbose {
logger.Info(format, args...)
}
}Log Rotation
import "gopkg.in/natefinch/lumberjack.v2"
func createRotatingLogger() (*pip.Logger, error) {
rotator := &lumberjack.Logger{
Filename: "pip-sdk.log",
MaxSize: 10, // MB
MaxBackups: 3,
MaxAge: 28, // days
Compress: true,
}
return pip.NewLogger(&pip.LoggerConfig{
Level: pip.LogLevelInfo,
Output: rotator,
})
}Performance Considerations
Check log level before expensive operations:
goif logger.IsEnabled(pip.LogLevelDebug) { expensiveDebugData := generateDebugData() logger.Debug("Debug data: %v", expensiveDebugData) }Use appropriate log levels:
Debug: Detailed debugging informationInfo: General operational informationWarn: Warning conditions that don't prevent operationError: Error conditions that prevent operationFatal: Critical errors that require program termination
Avoid logging in tight loops:
go// Bad for _, pkg := range packages { logger.Debug("Processing package: %s", pkg.Name) // ... process package } // Better logger.Debug("Processing %d packages", len(packages)) for _, pkg := range packages { // ... process package }
Thread Safety
The Logger is safe for concurrent use. Multiple goroutines can call logging methods simultaneously without additional synchronization.
Best Practices
Always close loggers that use files:
gologger, err := pip.NewLogger(config) if err != nil { return err } defer logger.Close()Use appropriate log levels for different environments:
govar logLevel pip.LogLevel if os.Getenv("DEBUG") == "true" { logLevel = pip.LogLevelDebug } else { logLevel = pip.LogLevelInfo }Include context in log messages:
gologger.Error("Failed to install package %s in environment %s: %v", pkg.Name, venvPath, err)Use structured logging for machine-readable logs:
gologger.Info("operation=install package=%s version=%s duration=%v success=%t", pkg.Name, pkg.Version, duration, success)