logging

package
v0.3.5 Latest Latest
Warning

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

Go to latest
Published: Mar 31, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package logging provides structured logging with distributed tracing support.

FinFocus uses zerolog for high-performance structured logging with automatic trace ID propagation through contexts.

Log Levels

  • TRACE: Property extraction, detailed calculations
  • DEBUG: Function entry/exit, retries, intermediate values
  • INFO: High-level operations (command start/end)
  • WARN: Recoverable issues (fallbacks, deprecations)
  • ERROR: Failures needing attention

Trace ID Management

Trace IDs are automatically generated or extracted from context:

traceID := logging.GetOrGenerateTraceID(ctx)
ctx = logging.ContextWithTraceID(ctx, traceID)

Component Loggers

Create sub-loggers for components:

logger = logging.ComponentLogger(logger, "registry")

Configuration

Logging can be configured via:

  • CLI flags (--debug)
  • Environment variables (FINFOCUS_LOG_LEVEL, FINFOCUS_LOG_FORMAT)
  • Config file (~/.finfocus/config.yaml)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ComponentLogger

func ComponentLogger(logger zerolog.Logger, component string) zerolog.Logger

ComponentLogger creates a logger derived from the provided logger with the `component` field set to the given component name. It returns the derived logger that will include `component` in all emitted entries.

func ContextWithAuditLogger

func ContextWithAuditLogger(ctx context.Context, logger AuditLogger) context.Context

ContextWithAuditLogger returns a copy of ctx that carries the provided AuditLogger under an internal package key.

func ContextWithPluginLogPath added in v0.3.0

func ContextWithPluginLogPath(ctx context.Context, path string) context.Context

ContextWithPluginLogPath stores the plugin log file path in the context. This path is propagated to plugin processes via FINFOCUS_LOG_FILE so that well-behaved plugins can configure their own structured logging to the same file.

func ContextWithPluginLogWriter added in v0.3.0

func ContextWithPluginLogWriter(ctx context.Context, w io.Writer) context.Context

ContextWithPluginLogWriter stores a writer for plugin log output in the context. This writer is used by plugin launchers to redirect plugin stderr/stdout to the core log file instead of the terminal.

func ContextWithTraceID

func ContextWithTraceID(ctx context.Context, traceID string) context.Context

ContextWithTraceID stores a trace ID in the context.

func FromContext

func FromContext(ctx context.Context) *zerolog.Logger

FromContext returns a logger from context, creating a default if none exists. FromContext returns a pointer to a zerolog.Logger associated with ctx, or a new default logger if none is present.

If no logger exists in the context, a default logger is created that writes to stderr, includes timestamps, and has the TracingHook applied so trace IDs from context are injected into log events. The default log level is taken from the environment variable named by pluginsdk.EnvLogLevel when valid; otherwise the level defaults to info. This function never returns nil.

func GenerateTraceID

func GenerateTraceID() string

GenerateTraceID creates a new OpenTelemetry-format trace identifier. This uses the pluginsdk's GenerateTraceID which produces a 32-character lowercase hexadecimal string, compatible with OpenTelemetry and W3C Trace Context.

func GetOrGenerateTraceID

func GetOrGenerateTraceID(ctx context.Context) string

GetOrGenerateTraceID returns a trace ID from environment, context, or generates a new one. Priority: FINFOCUS_TRACE_ID env var > context > generate new.

func IsSensitiveKey

func IsSensitiveKey(key string) bool

IsSensitiveKey checks if a key name contains sensitive patterns. IsSensitiveKey reports whether the provided parameter key is considered sensitive and should be redacted. It returns true if the key identifies sensitive data (for example, passwords, tokens, or keys), false otherwise.

func NewLogger

func NewLogger(cfg Config) zerolog.Logger

NewLogger creates a logger configured according to cfg. The logger includes timestamps and trace ID injection, respects cfg.Level, cfg.Format, cfg.Caller and cfg.StackTrace, and writes to the destination specified by cfg.Output (file, stdout, or stderr). If a file destination is selected but cannot be opened, the logger falls back to stderr.

func NewLoggerWithWriter

func NewLoggerWithWriter(cfg Config, writer io.Writer) zerolog.Logger

NewLoggerWithWriter creates a logger writing to the specified writer. This is primarily used for testing to capture log output.

func PluginLogPathFromContext added in v0.3.0

func PluginLogPathFromContext(ctx context.Context) string

PluginLogPathFromContext extracts the plugin log file path from context. Returns empty string if no path is stored.

func PluginLogWriterFromContext added in v0.3.0

func PluginLogWriterFromContext(ctx context.Context) io.Writer

PluginLogWriterFromContext extracts the plugin log writer from context. Returns nil if no writer is stored, indicating that plugin output should use the default behavior (stderr).

func PrintFallbackWarning

func PrintFallbackWarning(w io.Writer, reason string)

PrintFallbackWarning writes a single-line warning to w indicating that logging has fallen back to stderr. If reason is non-empty it is appended in parentheses after the message. The function ignores any write error.

func PrintLogPathMessage

func PrintLogPathMessage(w io.Writer, path string)

PrintLogPathMessage writes a "Logging to: <path>" message to the writer. PrintLogPathMessage writes "Logging to: <path>" followed by a newline to w. If path is empty, PrintLogPathMessage does nothing.

func SafeParams

func SafeParams(params map[string]string) map[string]string

SafeParams returns a shallow copy of params where values for keys identified as sensitive are replaced with "[REDACTED]". The returned map preserves all original keys; non-sensitive values are copied unchanged.

func SafeStr

func SafeStr(e *zerolog.Event, key, value string) *zerolog.Event

SafeStr adds a string field to the event, redacting sensitive values. Use this when logging potentially sensitive key-value pairs.

func TraceIDFromContext

func TraceIDFromContext(ctx context.Context) string

TraceIDFromContext extracts the trace ID from context. Returns empty string if no trace ID is stored.

Types

type AuditEntry

type AuditEntry struct {
	Timestamp   time.Time         // When the operation occurred
	TraceID     string            // Request correlation ID
	Command     string            // CLI command name (e.g., "cost projected")
	Parameters  map[string]string // Relevant parameters (file path, dates, etc.)
	Duration    time.Duration     // How long the operation took
	Success     bool              // Whether operation succeeded
	ResultCount int               // Number of results returned
	TotalCost   float64           // Total cost calculated (if applicable)
	Error       string            // Error message if failed
}

AuditEntry represents an audit log record for cost operations.

func NewAuditEntry

func NewAuditEntry(command, traceID string) *AuditEntry

NewAuditEntry creates a new AuditEntry with the given command and trace ID. NewAuditEntry creates a new AuditEntry with Timestamp set to the current UTC time and the provided command and traceID. It initializes Parameters as an empty map so callers can populate additional fields; use the With* builder methods to set duration, success, error, or parameters.

func (*AuditEntry) WithDuration

func (e *AuditEntry) WithDuration(start time.Time) *AuditEntry

WithDuration calculates and sets the duration from the given start time.

func (*AuditEntry) WithError

func (e *AuditEntry) WithError(errMsg string) *AuditEntry

WithError marks the entry as failed with the given error message.

func (*AuditEntry) WithParameters

func (e *AuditEntry) WithParameters(params map[string]string) *AuditEntry

WithParameters adds parameters to the audit entry.

func (*AuditEntry) WithSuccess

func (e *AuditEntry) WithSuccess(resultCount int, totalCost float64) *AuditEntry

WithSuccess marks the entry as successful with result count and total cost.

type AuditLogger

type AuditLogger interface {
	// Log writes an audit entry.
	Log(ctx context.Context, entry AuditEntry)

	// Enabled returns whether audit logging is active.
	Enabled() bool

	// Close releases any resources held by the logger (e.g., file handles).
	Close() error
}

AuditLogger writes audit entries.

func AuditLoggerFromContext

func AuditLoggerFromContext(ctx context.Context) AuditLogger

AuditLoggerFromContext extracts the AuditLogger from context. AuditLoggerFromContext retrieves the AuditLogger stored in ctx. It returns the AuditLogger found in the context, or a no-op AuditLogger if none is present.

func NewAuditLogger

func NewAuditLogger(cfg AuditLoggerConfig) AuditLogger

NewAuditLogger creates a new AuditLogger with the given configuration.

NewAuditLogger creates an AuditLogger according to cfg. If cfg.Enabled is false, NewAuditLogger returns a no-op logger. If cfg.Writer is provided it is used as the destination; otherwise, if cfg.File is set the file is opened for append and used as the destination. If opening cfg.File fails or neither Writer nor File are provided, stderr is used as the destination. The returned logger emits structured audit records and reports Enabled() == true when auditing is active. Callers should call Close() when done to release any file handles.

func NoOpAuditLogger

func NoOpAuditLogger() AuditLogger

NoOpAuditLogger returns an AuditLogger that performs no operations. The returned logger's Log method is a no-op and Enabled reports false.

type AuditLoggerConfig

type AuditLoggerConfig struct {
	Enabled bool      // Enable audit logging
	Writer  io.Writer // Where to write audit logs (nil uses os.Stderr)
	File    string    // Optional: separate audit file path
}

AuditLoggerConfig holds configuration for creating an AuditLogger.

type CategorizedError

type CategorizedError struct {
	Category ErrorCategory
	Message  string
	Solution string
	Context  map[string]string
	Cause    error
}

CategorizedError represents an error with category, solution, and context.

func DeveloperError

func DeveloperError(message, solution string, cause error) *CategorizedError

DeveloperError creates a developer error with debugging information.

func FileSystemError

func FileSystemError(operation, path string, cause error) *CategorizedError

FileSystemError creates an error for filesystem operations.

func InvalidArgumentError

func InvalidArgumentError(arg string, cause error) *CategorizedError

InvalidArgumentError creates an error for invalid CLI arguments.

func InvalidPulumiJSONError

func InvalidPulumiJSONError(path string, cause error) *CategorizedError

InvalidPulumiJSONError creates an error for invalid Pulumi JSON.

func MissingConfigError

func MissingConfigError(configKey string, cause error) *CategorizedError

MissingConfigError creates an error for missing configuration.

func NetworkError

func NetworkError(operation string, cause error) *CategorizedError

NetworkError creates an error for network connectivity issues.

func PluginBugError

func PluginBugError(pluginName, operation string, cause error) *CategorizedError

PluginBugError creates an error for plugin implementation bugs.

func PluginCommunicationError

func PluginCommunicationError(pluginName string, cause error) *CategorizedError

PluginCommunicationError creates an error for plugin communication failures.

func PluginNotFoundError

func PluginNotFoundError(pluginName string, cause error) *CategorizedError

PluginNotFoundError creates an error for missing plugins.

func ProtocolMismatchError

func ProtocolMismatchError(pluginName, expectedVersion, actualVersion string) *CategorizedError

ProtocolMismatchError creates an error for protocol version mismatches.

func SystemError

func SystemError(message, solution string, cause error) *CategorizedError

SystemError creates a system error with troubleshooting guidance.

func UserError

func UserError(message, solution string, cause error) *CategorizedError

UserError creates a user-facing error with helpful guidance.

func (*CategorizedError) Error

func (e *CategorizedError) Error() string

Error implements the error interface.

func (*CategorizedError) Unwrap

func (e *CategorizedError) Unwrap() error

Unwrap returns the cause error for error wrapping.

func (*CategorizedError) WithContext

func (e *CategorizedError) WithContext(key, value string) *CategorizedError

WithContext adds contextual information to the error. It returns a new error with the additional context to maintain immutability.

type Config

type Config struct {
	Level      string // Log level: trace, debug, info, warn, error
	Format     string // Output format: json, console, text
	Output     string // Output destination: stderr, stdout, file
	File       string // File path when Output is "file"
	Caller     bool   // Include file:line in output
	StackTrace bool   // Include stack trace on errors
}

Config holds logging configuration settings.

type ErrorCategory

type ErrorCategory string

ErrorCategory represents the type of error for better user guidance.

const (
	// ErrorCategoryUser indicates user-facing errors (invalid input, configuration).
	ErrorCategoryUser ErrorCategory = "USER"

	// ErrorCategorySystem indicates system errors (network, filesystem, permissions).
	ErrorCategorySystem ErrorCategory = "SYSTEM"

	// ErrorCategoryDeveloper indicates developer errors (bugs, protocol mismatches).
	ErrorCategoryDeveloper ErrorCategory = "DEVELOPER"
)

type LogPathResult

type LogPathResult struct {
	Logger         zerolog.Logger // The created logger
	FilePath       string         // Path to log file (empty if not using file)
	UsingFile      bool           // True if logging to file
	FallbackUsed   bool           // True if fallback to stderr occurred
	FallbackReason string         // Reason for fallback (if any)
	// contains filtered or unexported fields
}

LogPathResult contains the result of logger creation with file path information. This allows the CLI to communicate log file location to operators. Callers should call Close() when done to release any file handles.

func NewLoggerWithPath

func NewLoggerWithPath(cfg Config) LogPathResult

NewLoggerWithPath creates a zerolog logger according to cfg and reports the chosen log destination.

If cfg.Output is "file" and cfg.File is non-empty, NewLoggerWithPath attempts to open or create the specified file and, on success, returns a logger that writes to that file and sets LogPathResult.FilePath and LogPathResult.UsingFile = true. If opening the file fails, the function falls back to stderr, sets LogPathResult.FallbackUsed = true and LogPathResult.FallbackReason to the error string, and returns a logger that writes to stderr. If cfg.File is empty the function uses stderr.

If cfg.Output is "stdout" the returned logger writes to stdout. For any other cfg.Output value the returned logger writes to stderr.

The returned LogPathResult contains the constructed Logger and metadata describing whether a file was used, the file path (if any), and whether a fallback to stderr occurred with its reason.

func (*LogPathResult) Close

func (r *LogPathResult) Close() error

Close releases any resources held by the logger (e.g., file handles).

func (*LogPathResult) SetPluginLogFile added in v0.3.0

func (r *LogPathResult) SetPluginLogFile(f *os.File)

SetPluginLogFile stores a separate file handle for plugin I/O redirection. This handle is closed when Close() is called.

type LoggingConfig

type LoggingConfig = Config

LoggingConfig is an alias for Config for backward compatibility.

type PhaseTimer added in v0.3.1

type PhaseTimer struct {
	// contains filtered or unexported fields
}

PhaseTimer tracks elapsed time for named phases within a multi-step operation. Use StartPhase to begin timing a phase, then call Done on the returned PhaseTimer to log the phase completion with duration_ms.

func StartPhase added in v0.3.1

func StartPhase(ctx context.Context, component, operation, phase string) PhaseTimer

StartPhase begins timing a named phase within an operation. Call Done on the returned PhaseTimer to log completion with duration_ms. The phase start is logged at Debug level; completion is logged at Info level.

func (PhaseTimer) Done added in v0.3.1

func (t PhaseTimer) Done(ctx context.Context)

Done logs the phase completion at Info level with the elapsed time in milliseconds.

func (PhaseTimer) Elapsed added in v0.3.1

func (t PhaseTimer) Elapsed() time.Duration

Elapsed returns the duration since the phase started.

type TracingHook

type TracingHook struct{}

TracingHook implements zerolog.Hook to automatically inject trace_id from context.

func (TracingHook) Run

func (h TracingHook) Run(e *zerolog.Event, _ zerolog.Level, _ string)

Run implements zerolog.Hook interface. It extracts trace_id from the event's context and adds it to the log entry.

Jump to

Keyboard shortcuts

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