ax(batch): expand abbreviated receiver names (AX Principle 1)

Rename short receivers to predictable full names across all packages:
- lb -> logBuffer (LogBuffer methods in miner.go)
- l -> logger (Logger methods in logging/logger.go)
- l -> level (Level.String() in logging/logger.go)
- h -> histogram (LatencyHistogram methods in metrics.go)
- r -> repository (FileRepository methods in repository.go)

Agents can now grep for the receiver name and get the type without
context. Single-letter 'c', 'm', 's', 'e' kept where idiomatic for
Container, Miner, Store, and Error types per Go convention.

Co-Authored-By: Charon <charon@lethean.io>
This commit is contained in:
Claude 2026-04-02 18:05:42 +01:00
parent 132b69426a
commit 93a825c7da
No known key found for this signature in database
GPG key ID: AF404715446AEB41
4 changed files with 108 additions and 108 deletions

View file

@ -22,8 +22,8 @@ const (
// logging.LevelDebug.String() // "DEBUG"
// logging.LevelError.String() // "ERROR"
func (l Level) String() string {
switch l {
func (level Level) String() string {
switch level {
case LevelDebug:
return "DEBUG"
case LevelInfo:
@ -78,40 +78,40 @@ func New(config Config) *Logger {
// WithComponent returns a child logger scoped to a sub-system.
// child := logger.WithComponent("xmrig")
// child.Info("miner started")
func (l *Logger) WithComponent(component string) *Logger {
func (logger *Logger) WithComponent(component string) *Logger {
return &Logger{
output: l.output,
level: l.level,
output: logger.output,
level: logger.level,
component: component,
}
}
// SetLevel adjusts the minimum level for subsequent log calls.
// logger.SetLevel(logging.LevelDebug)
func (l *Logger) SetLevel(level Level) {
l.mutex.Lock()
defer l.mutex.Unlock()
l.level = level
func (logger *Logger) SetLevel(level Level) {
logger.mutex.Lock()
defer logger.mutex.Unlock()
logger.level = level
}
// GetLevel returns the current minimum log level.
// current := logger.GetLevel()
// if current == logging.LevelDebug { logger.SetLevel(logging.LevelInfo) }
func (l *Logger) GetLevel() Level {
l.mutex.Lock()
defer l.mutex.Unlock()
return l.level
func (logger *Logger) GetLevel() Level {
logger.mutex.Lock()
defer logger.mutex.Unlock()
return logger.level
}
// logger.Info("started", logging.Fields{"miner": "xmrig", "pool": "pool.lthn.io"})
type Fields map[string]interface{}
// log writes a log message at the specified level.
func (l *Logger) log(level Level, msg string, fields Fields) {
l.mutex.Lock()
defer l.mutex.Unlock()
func (logger *Logger) log(level Level, msg string, fields Fields) {
logger.mutex.Lock()
defer logger.mutex.Unlock()
if level < l.level {
if level < logger.level {
return
}
@ -123,9 +123,9 @@ func (l *Logger) log(level Level, msg string, fields Fields) {
builder.WriteString(level.String())
builder.WriteString("]")
if l.component != "" {
if logger.component != "" {
builder.WriteString(" [")
builder.WriteString(l.component)
builder.WriteString(logger.component)
builder.WriteString("]")
}
@ -144,47 +144,47 @@ func (l *Logger) log(level Level, msg string, fields Fields) {
}
builder.WriteString("\n")
fmt.Fprint(l.output, builder.String())
fmt.Fprint(logger.output, builder.String())
}
// logger.Debug("hashrate collected", logging.Fields{"rate": 1234})
func (l *Logger) Debug(msg string, fields ...Fields) {
l.log(LevelDebug, msg, mergeFields(fields))
func (logger *Logger) Debug(msg string, fields ...Fields) {
logger.log(LevelDebug, msg, mergeFields(fields))
}
// logger.Info("miner started", logging.Fields{"miner": "xmrig"})
func (l *Logger) Info(msg string, fields ...Fields) {
l.log(LevelInfo, msg, mergeFields(fields))
func (logger *Logger) Info(msg string, fields ...Fields) {
logger.log(LevelInfo, msg, mergeFields(fields))
}
// logger.Warn("hashrate drop", logging.Fields{"current": 500, "min": 1000})
func (l *Logger) Warn(msg string, fields ...Fields) {
l.log(LevelWarn, msg, mergeFields(fields))
func (logger *Logger) Warn(msg string, fields ...Fields) {
logger.log(LevelWarn, msg, mergeFields(fields))
}
// logger.Error("miner crashed", logging.Fields{"code": -1, "miner": "xmrig"})
func (l *Logger) Error(msg string, fields ...Fields) {
l.log(LevelError, msg, mergeFields(fields))
func (logger *Logger) Error(msg string, fields ...Fields) {
logger.log(LevelError, msg, mergeFields(fields))
}
// logger.Debugf("collected %d hashrate points for %s", len(points), minerName)
func (l *Logger) Debugf(format string, args ...interface{}) {
l.log(LevelDebug, fmt.Sprintf(format, args...), nil)
func (logger *Logger) Debugf(format string, args ...interface{}) {
logger.log(LevelDebug, fmt.Sprintf(format, args...), nil)
}
// logger.Infof("miner %s started on pool %s", minerName, poolURL)
func (l *Logger) Infof(format string, args ...interface{}) {
l.log(LevelInfo, fmt.Sprintf(format, args...), nil)
func (logger *Logger) Infof(format string, args ...interface{}) {
logger.log(LevelInfo, fmt.Sprintf(format, args...), nil)
}
// logger.Warnf("hashrate %d H/s below minimum %d H/s", current, minimum)
func (l *Logger) Warnf(format string, args ...interface{}) {
l.log(LevelWarn, fmt.Sprintf(format, args...), nil)
func (logger *Logger) Warnf(format string, args ...interface{}) {
logger.log(LevelWarn, fmt.Sprintf(format, args...), nil)
}
// logger.Errorf("failed to connect to pool %s: %v", poolURL, err)
func (l *Logger) Errorf(format string, args ...interface{}) {
l.log(LevelError, fmt.Sprintf(format, args...), nil)
func (logger *Logger) Errorf(format string, args ...interface{}) {
logger.log(LevelError, fmt.Sprintf(format, args...), nil)
}
// combined := mergeFields([]Fields{{"a": 1}, {"b": 2}}) // Fields{"a": 1, "b": 2}

View file

@ -51,39 +51,39 @@ func NewLatencyHistogram(maxSize int) *LatencyHistogram {
}
// h.Record(42 * time.Millisecond) // call after each request completes
func (h *LatencyHistogram) Record(d time.Duration) {
h.mutex.Lock()
defer h.mutex.Unlock()
func (histogram *LatencyHistogram) Record(d time.Duration) {
histogram.mutex.Lock()
defer histogram.mutex.Unlock()
if len(h.samples) >= h.maxSize {
if len(histogram.samples) >= histogram.maxSize {
// Ring buffer behavior - overwrite oldest
copy(h.samples, h.samples[1:])
h.samples = h.samples[:len(h.samples)-1]
copy(histogram.samples, histogram.samples[1:])
histogram.samples = histogram.samples[:len(histogram.samples)-1]
}
h.samples = append(h.samples, d)
histogram.samples = append(histogram.samples, d)
}
// avg := h.Average() // returns 0 if no samples recorded
func (h *LatencyHistogram) Average() time.Duration {
h.mutex.Lock()
defer h.mutex.Unlock()
func (histogram *LatencyHistogram) Average() time.Duration {
histogram.mutex.Lock()
defer histogram.mutex.Unlock()
if len(h.samples) == 0 {
if len(histogram.samples) == 0 {
return 0
}
var total time.Duration
for _, d := range h.samples {
for _, d := range histogram.samples {
total += d
}
return total / time.Duration(len(h.samples))
return total / time.Duration(len(histogram.samples))
}
// if h.Count() == 0 { return } // guard before calling Average()
func (h *LatencyHistogram) Count() int {
h.mutex.Lock()
defer h.mutex.Unlock()
return len(h.samples)
func (histogram *LatencyHistogram) Count() int {
histogram.mutex.Lock()
defer histogram.mutex.Unlock()
return len(histogram.samples)
}
// mining.DefaultMetrics.MinersStarted.Load()

View file

@ -43,9 +43,9 @@ func NewLogBuffer(maxLines int) *LogBuffer {
const maxLineLength = 2000
// cmd.Stdout = lb // satisfies io.Writer; timestamps and ring-buffers each line
func (lb *LogBuffer) Write(p []byte) (n int, err error) {
lb.mutex.Lock()
defer lb.mutex.Unlock()
func (logBuffer *LogBuffer) Write(p []byte) (n int, err error) {
logBuffer.mutex.Lock()
defer logBuffer.mutex.Unlock()
// Split input into lines
text := string(p)
@ -61,33 +61,33 @@ func (lb *LogBuffer) Write(p []byte) (n int, err error) {
}
// Add timestamp prefix
timestampedLine := "[" + time.Now().Format("15:04:05") + "] " + line
lb.lines = append(lb.lines, timestampedLine)
logBuffer.lines = append(logBuffer.lines, timestampedLine)
// Trim if over max - force reallocation to release memory
if len(lb.lines) > lb.maxLines {
newSlice := make([]string, lb.maxLines)
copy(newSlice, lb.lines[len(lb.lines)-lb.maxLines:])
lb.lines = newSlice
if len(logBuffer.lines) > logBuffer.maxLines {
newSlice := make([]string, logBuffer.maxLines)
copy(newSlice, logBuffer.lines[len(logBuffer.lines)-logBuffer.maxLines:])
logBuffer.lines = newSlice
}
}
return len(p), nil
}
// lines := lb.GetLines()
// lines := logBuffer.GetLines()
// response.Logs = lines[max(0, len(lines)-100):]
func (lb *LogBuffer) GetLines() []string {
lb.mutex.RLock()
defer lb.mutex.RUnlock()
result := make([]string, len(lb.lines))
copy(result, lb.lines)
func (logBuffer *LogBuffer) GetLines() []string {
logBuffer.mutex.RLock()
defer logBuffer.mutex.RUnlock()
result := make([]string, len(logBuffer.lines))
copy(result, logBuffer.lines)
return result
}
// lb.Clear() // called on miner Stop() to release memory
func (lb *LogBuffer) Clear() {
lb.mutex.Lock()
defer lb.mutex.Unlock()
lb.lines = lb.lines[:0]
// logBuffer.Clear() // called on miner Stop() to release memory
func (logBuffer *LogBuffer) Clear() {
logBuffer.mutex.Lock()
defer logBuffer.mutex.Unlock()
logBuffer.lines = logBuffer.lines[:0]
}
// type XMRigMiner struct { BaseMiner }

View file

@ -33,35 +33,35 @@ type FileRepositoryOption[T any] func(*FileRepository[T])
// repo := NewFileRepository[MinersConfig](path, WithDefaults(defaultMinersConfig))
func WithDefaults[T any](fn func() T) FileRepositoryOption[T] {
return func(r *FileRepository[T]) {
r.defaults = fn
return func(repo *FileRepository[T]) {
repo.defaults = fn
}
}
// repo := NewFileRepository[MinersConfig](path, WithDefaults(defaultMinersConfig))
func NewFileRepository[T any](path string, options ...FileRepositoryOption[T]) *FileRepository[T] {
r := &FileRepository[T]{
repo := &FileRepository[T]{
path: path,
}
for _, option := range options {
option(r)
option(repo)
}
return r
return repo
}
// data, err := repo.Load()
// if err != nil { return defaults, err }
func (r *FileRepository[T]) Load() (T, error) {
r.mutex.RLock()
defer r.mutex.RUnlock()
func (repository *FileRepository[T]) Load() (T, error) {
repository.mutex.RLock()
defer repository.mutex.RUnlock()
var result T
data, err := os.ReadFile(r.path)
data, err := os.ReadFile(repository.path)
if err != nil {
if os.IsNotExist(err) {
if r.defaults != nil {
return r.defaults(), nil
if repository.defaults != nil {
return repository.defaults(), nil
}
return result, nil
}
@ -76,16 +76,16 @@ func (r *FileRepository[T]) Load() (T, error) {
}
// if err := repo.Save(updated); err != nil { return ErrInternal("save").WithCause(err) }
func (r *FileRepository[T]) Save(data T) error {
r.mutex.Lock()
defer r.mutex.Unlock()
func (repository *FileRepository[T]) Save(data T) error {
repository.mutex.Lock()
defer repository.mutex.Unlock()
return r.saveUnlocked(data)
return repository.saveUnlocked(data)
}
// return r.saveUnlocked(data) // called by Save and Update while mutex is held
func (r *FileRepository[T]) saveUnlocked(data T) error {
dir := filepath.Dir(r.path)
// return repository.saveUnlocked(data) // called by Save and Update while mutex is held
func (repository *FileRepository[T]) saveUnlocked(data T) error {
dir := filepath.Dir(repository.path)
if err := os.MkdirAll(dir, 0755); err != nil {
return ErrInternal("failed to create directory").WithCause(err)
}
@ -95,24 +95,24 @@ func (r *FileRepository[T]) saveUnlocked(data T) error {
return ErrInternal("failed to marshal data").WithCause(err)
}
return AtomicWriteFile(r.path, jsonData, 0600)
return AtomicWriteFile(repository.path, jsonData, 0600)
}
// repo.Update(func(configuration *MinersConfig) error {
// configuration.Miners = append(configuration.Miners, entry)
// return nil
// })
func (r *FileRepository[T]) Update(fn func(*T) error) error {
r.mutex.Lock()
defer r.mutex.Unlock()
func (repository *FileRepository[T]) Update(fn func(*T) error) error {
repository.mutex.Lock()
defer repository.mutex.Unlock()
// Load current data
var data T
fileData, err := os.ReadFile(r.path)
fileData, err := os.ReadFile(repository.path)
if err != nil {
if os.IsNotExist(err) {
if r.defaults != nil {
data = r.defaults()
if repository.defaults != nil {
data = repository.defaults()
}
} else {
return ErrInternal("failed to read file").WithCause(err)
@ -129,29 +129,29 @@ func (r *FileRepository[T]) Update(fn func(*T) error) error {
}
// Save atomically
return r.saveUnlocked(data)
return repository.saveUnlocked(data)
}
// path := repo.Path() // => "/home/user/.config/lethean-desktop/miners.json"
func (r *FileRepository[T]) Path() string {
return r.path
func (repository *FileRepository[T]) Path() string {
return repository.path
}
// if !repo.Exists() { return defaults, nil }
func (r *FileRepository[T]) Exists() bool {
r.mutex.RLock()
defer r.mutex.RUnlock()
func (repository *FileRepository[T]) Exists() bool {
repository.mutex.RLock()
defer repository.mutex.RUnlock()
_, err := os.Stat(r.path)
_, err := os.Stat(repository.path)
return err == nil
}
// if err := repo.Delete(); err != nil { return err }
func (r *FileRepository[T]) Delete() error {
r.mutex.Lock()
defer r.mutex.Unlock()
func (repository *FileRepository[T]) Delete() error {
repository.mutex.Lock()
defer repository.mutex.Unlock()
err := os.Remove(r.path)
err := os.Remove(repository.path)
if os.IsNotExist(err) {
return nil
}