Skip to main content

Error Handling & Logging

Error Types and Handling

Standard Error Types
enum ErrorType {
  VALIDATION_ERROR = 'VALIDATION_ERROR',
  AUTHENTICATION_ERROR = 'AUTHENTICATION_ERROR', 
  AUTHORIZATION_ERROR = 'AUTHORIZATION_ERROR',
  BLOCKCHAIN_ERROR = 'BLOCKCHAIN_ERROR',
  BUSINESS_LOGIC_ERROR = 'BUSINESS_LOGIC_ERROR',
  EXTERNAL_SERVICE_ERROR = 'EXTERNAL_SERVICE_ERROR',
  SYSTEM_ERROR = 'SYSTEM_ERROR'
}

interface BaseError extends Error {
  type: ErrorType;
  code: string;
  details?: Record<string, any>;
  timestamp: string;
  correlationId: string;
}

class VaultError extends BaseError {
  constructor(type: ErrorType, code: string, message: string, details?: Record<string, any>) {
    super(message);
    this.type = type;
    this.code = code;
    this.details = details;
    this.timestamp = new Date().toISOString();
    this.correlationId = getCurrentCorrelationId();
  }
}
Error Implementation
// Error throwing
async function createVault(params: VaultParams) {
  try {
    await validateVaultParams(params);
  } catch (error) {
    throw new VaultError(
      ErrorType.VALIDATION_ERROR,
      'INVALID_VAULT_PARAMS',
      'Invalid vault parameters provided',
      { params, validationErrors: error.details }
    );
  }
}

// Error handling middleware
app.use((error: Error, req: Request, res: Response, next: NextFunction) => {
  if (error instanceof VaultError) {
    logger.error('Vault operation failed', {
      type: error.type,
      code: error.code,
      message: error.message,
      details: error.details,
      correlationId: error.correlationId
    });

    return res.status(getHttpStatus(error.type)).json({
      status: 'error',
      error: {
        code: error.code,
        message: error.message,
        correlationId: error.correlationId
      }
    });
  }
  next(error);
});

Logging Implementation

Logger Configuration
import winston from 'winston';
import { ElasticsearchTransport } from 'winston-elasticsearch';

const logger = winston.createLogger({
  level: process.env.LOG_LEVEL || 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  defaultMeta: { service: 'vault-service' },
  transports: [
    new winston.transports.Console(),
    new ElasticsearchTransport({
      level: 'info',
      clientOpts: {
        node: process.env.ELASTICSEARCH_URL,
        auth: {
          username: process.env.ELASTICSEARCH_USERNAME,
          password: process.env.ELASTICSEARCH_PASSWORD
        }
      },
      index: 'vault-logs-${process.env.NODE_ENV}-%{YYYY.MM.DD}',
      mappingTemplate: {
        index_patterns: ['vault-logs-*'],
        settings: {
          number_of_shards: 1,
          number_of_replicas: 1
        },
        mappings: {
          properties: {
            '@timestamp': { type: 'date' },
            level: { type: 'keyword' },
            message: { type: 'text' },
            correlationId: { type: 'keyword' },
            type: { type: 'keyword' },
            code: { type: 'keyword' },
            details: { type: 'object' }
          }
        }
      }
    })
  ]
});
Structured Logging
// Request logging middleware
app.use((req: Request, res: Response, next: NextFunction) => {
  const correlationId = generateCorrelationId();
  setCurrentCorrelationId(correlationId);

  logger.info('Incoming request', {
    method: req.method,
    path: req.path,
    correlationId,
    ip: req.ip,
    userAgent: req.get('user-agent')
  });

  next();
});

// Business operation logging
async function executeProposal(proposalId: string) {
  logger.info('Starting proposal execution', {
    proposalId,
    correlationId: getCurrentCorrelationId()
  });

  try {
    const result = await performExecution(proposalId);
    
    logger.info('Proposal execution completed', {
      proposalId,
      result,
      correlationId: getCurrentCorrelationId()
    });
    
    return result;
  } catch (error) {
    logger.error('Proposal execution failed', {
      proposalId,
      error: error.message,
      stack: error.stack,
      correlationId: getCurrentCorrelationId()
    });
    throw error;
  }
}

ELK Stack Configuration

Logstash Pipeline
input {
  beats {
    port => 5044
  }
}

filter {
  json {
    source => "message"
  }
  
  date {
    match => [ "@timestamp", "ISO8601" ]
  }
  
  if [type] == "BLOCKCHAIN_ERROR" {
    grok {
      match => { "message" => "%{GREEDYDATA:transaction_hash}" }
    }
  }
}

output {
  elasticsearch {
    hosts => ["elasticsearch:9200"]
    index => "vault-logs-%{+YYYY.MM.dd}"
    document_type => "_doc"
  }
}
ElasticSearch Index Template
{
  "index_patterns": ["vault-logs-*"],
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1,
    "index.refresh_interval": "5s"
  },
  "mappings": {
    "properties": {
      "@timestamp": { "type": "date" },
      "service": { "type": "keyword" },
      "level": { "type": "keyword" },
      "correlationId": { "type": "keyword" },
      "type": { "type": "keyword" },
      "code": { "type": "keyword" },
      "message": { "type": "text" },
      "details": {
        "type": "object",
        "dynamic": true
      },
      "trace": {
        "properties": {
          "stack": { "type": "text" },
          "method": { "type": "keyword" },
          "line": { "type": "integer" }
        }
      },
      "request": {
        "properties": {
          "method": { "type": "keyword" },
          "path": { "type": "keyword" },
          "ip": { "type": "ip" },
          "userAgent": { "type": "text" }
        }
      }
    }
  }
}
Kibana Error Monitoring Dashboard
{
  "title": "Vault Error Monitoring",
  "panels": [
    {
      "type": "visualization",
      "title": "Errors by Type",
      "visualization": {
        "type": "pie",
        "aggs": [
          { "type": "count", "schema": "metric" },
          { "type": "terms", "field": "type", "schema": "segment" }
        ]
      }
    },
    {
      "type": "visualization", 
      "title": "Error Timeline",
      "visualization": {
        "type": "line",
        "aggs": [
          { "type": "count", "schema": "metric" },
          { "type": "date_histogram", "field": "@timestamp", "schema": "segment" }
        ]
      }
    }
  ]
}

Implementation Guidelines

Best Practices

1. Error Handling
- Use custom error classes
- Include correlation IDs
- Add contextual details
- Handle errors at boundaries
- Never expose internal errors

2. Logging
- Use structured logging
- Include correlation IDs
- Log at appropriate levels
- Avoid sensitive data
- Add business context

3. Monitoring
- Set up alerting
- Monitor error rates
- Track response times
- Watch resource usage
- Set up dashboards

4. Security
- Sanitize logged data
- Encrypt sensitive logs
- Implement log retention
- Control log access
- Monitor suspicious patterns

Getting Started

1. Install Dependencies

npm install winston winston-elasticsearch @elastic/elasticsearch

2. Configure Environment

# .env file
ELASTICSEARCH_URL=http://localhost:9200
ELASTICSEARCH_USERNAME=elastic
ELASTICSEARCH_PASSWORD=changeme
LOG_LEVEL=info

3. Set Up ELK Stack

docker-compose up -d elasticsearch logstash kibana

4. Initialize Templates

curl -X PUT "localhost:9200/_template/vault-logs" -H "Content-Type: application/json" -d @template.json

5. Verify Setup

# Test logging
logger.info('Test log entry');

# Check Elasticsearch
curl -X GET "localhost:9200/vault-logs-*/_search"