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() string
Returns 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() *LoggerConfig
Returns 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 program
Specialized 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() LogLevel
Returns the current log level.
IsEnabled
func (l *Logger) IsEnabled(level LogLevel) bool
Checks 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() error
Closes 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 - message
Example 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)