# Logging Quick Reference

## API Signatures

```typescript
// Factory
function logger(ctx?: MaybeLoggerContextFn): LoggerApi

// Logger API
interface LoggerApi {
  trace(message: string, context?: MaybeLoggerContextFn): void;
  debug(message: string, context?: MaybeLoggerContextFn): void;
  info(message: string, context?: MaybeLoggerContextFn): void;
  warn(message: string, context?: MaybeLoggerContextFn): void;
  error(message: string, error?: Error, context?: MaybeLoggerContextFn): void;
}

// Types
type MaybeLoggerContextFn = LoggerContext | (() => LoggerContext);
interface LoggerContext { [key: string]: unknown; }
```

## Common Patterns

| Pattern | Code |
|---------|------|
| Basic logger | `#logger = logger()` |
| Static context | `#logger = logger({ component: 'Name' })` |
| Dynamic context | `#logger = logger(() => ({ id: this.id }))` |
| Log info | `this.#logger.info('Message')` |
| Log with context | `this.#logger.info('Message', () => ({ key: value }))` |
| Log error | `this.#logger.error('Error', error)` |
| Error with context | `this.#logger.error('Error', error, () => ({ id }))` |
| Component context | `providers: [provideLoggerContext({ feature: 'x' })]` |

## Configuration

```typescript
// app.config.ts
import { provideLogging, withLogLevel, withSink, withContext,
         LogLevel, ConsoleLogSink } from '@isa/core/logging';

export const appConfig: ApplicationConfig = {
  providers: [
    provideLogging(
      withLogLevel(isDevMode() ? LogLevel.Debug : LogLevel.Warn),
      withSink(ConsoleLogSink),
      withContext({ app: 'ISA', version: '1.0.0' })
    )
  ]
};
```

## Log Levels

| Level | Use Case | Example |
|-------|----------|---------|
| `Trace` | Method entry/exit | `this.#logger.trace('Entering processData')` |
| `Debug` | Development info | `this.#logger.debug('Variable state', () => ({ x }))` |
| `Info` | Runtime events | `this.#logger.info('User logged in', { userId })` |
| `Warn` | Warnings | `this.#logger.warn('Deprecated API used')` |
| `Error` | Errors | `this.#logger.error('Operation failed', error)` |
| `Off` | Disable logging | `withLogLevel(LogLevel.Off)` |

## Decision Trees

### Context Type Decision
```
Value changes at runtime?
├─ Yes → () => ({ value: this.getValue() })
└─ No  → { value: 'static' }

Computing value is expensive?
├─ Yes → () => ({ data: this.compute() })
└─ No  → Either works
```

### Log Level Decision
```
Method flow details? → Trace
Development debug?  → Debug
Runtime information? → Info
Potential problem?  → Warn
Error occurred?     → Error
```

## Performance Tips

```typescript
// ✅ DO: Lazy evaluation
this.#logger.debug('Data', () => ({
  result: this.expensive() // Only runs if debug enabled
}));

// ❌ DON'T: Eager evaluation
this.#logger.debug('Data', {
  result: this.expensive() // Always runs
});

// ✅ DO: Log aggregates
this.#logger.info('Batch done', () => ({ count: items.length }));

// ❌ DON'T: Log in loops
for (const item of items) {
  this.#logger.debug('Item', { item }); // Performance hit
}
```

## Testing

```typescript
import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
import { LoggingService } from '@isa/core/logging';

describe('MyComponent', () => {
  const createComponent = createComponentFactory({
    component: MyComponent,
    mocks: [LoggingService]
  });

  it('logs error', () => {
    const spectator = createComponent();
    const logger = spectator.inject(LoggingService);

    spectator.component.operation();

    expect(logger.error).toHaveBeenCalled();
  });
});
```

## Custom Sink

```typescript
import { Injectable } from '@angular/core';
import { Sink, LogLevel, LoggerContext } from '@isa/core/logging';

@Injectable()
export class CustomSink implements Sink {
  log(level: LogLevel, message: string, context?: LoggerContext, error?: Error): void {
    // Implementation
  }
}

// Register
provideLogging(withSink(CustomSink))
```

## Sink Function (with DI)

```typescript
import { inject } from '@angular/core';
import { SinkFn, LogLevel } from '@isa/core/logging';

export const remoteSink: SinkFn = () => {
  const http = inject(HttpClient);

  return (level, message, context, error) => {
    if (level === LogLevel.Error) {
      http.post('/api/logs', { level, message, context, error }).subscribe();
    }
  };
};

// Register
provideLogging(withSinkFn(remoteSink))
```

## Common Imports

```typescript
// Main imports
import { logger, provideLoggerContext } from '@isa/core/logging';

// Configuration imports
import {
  provideLogging,
  withLogLevel,
  withSink,
  withContext,
  LogLevel,
  ConsoleLogSink
} from '@isa/core/logging';

// Type imports
import {
  LoggerApi,
  Sink,
  SinkFn,
  LoggerContext
} from '@isa/core/logging';
```
