Skip to content

Log Analysis Examples ​

Real-world examples of analyzing large log files efficiently.

Overview ​

Log files can grow to gigabytes in production environments. This guide demonstrates practical patterns for analyzing logs using Large File MCP Server without memory issues.

Basic Log Analysis ​

Find All Errors ​

Search for errors with surrounding context:

typescript
const errors = await search_in_large_file({
  filePath: "/var/log/app.log",
  pattern: "ERROR|FATAL",
  regex: true,
  contextBefore: 3,
  contextAfter: 3,
  maxResults: 50
});

console.log(`Found ${errors.totalMatches} errors`);
errors.matches.forEach(match => {
  console.log(`Line ${match.lineNumber}: ${match.line}`);
  console.log("Context before:", match.contextBefore);
  console.log("Context after:", match.contextAfter);
  console.log("---");
});

Analyze Error Frequency ​

Count errors by time period:

typescript
const stream = stream_large_file({
  filePath: "/var/log/app.log",
  chunkSize: 1000
});

const errorsByHour = new Map<string, number>();

for await (const chunk of stream) {
  for (const line of chunk.lines) {
    if (line.includes("ERROR")) {
      // Extract timestamp: "2024-01-10 15:23:45"
      const timeMatch = line.match(/(\d{4}-\d{2}-\d{2}\s+\d{2}):/);
      if (timeMatch) {
        const hour = timeMatch[1];
        errorsByHour.set(hour, (errorsByHour.get(hour) || 0) + 1);
      }
    }
  }
}

// Display results
console.log("Errors by hour:");
Array.from(errorsByHour.entries())
  .sort(([a], [b]) => a.localeCompare(b))
  .forEach(([hour, count]) => {
    console.log(`${hour}:00 - ${count} errors`);
  });

Advanced Patterns ​

Database Error Investigation ​

Find database connection issues with full context:

typescript
async function investigateDatabaseErrors(logFile: string) {
  // Step 1: Find database errors
  const errors = await search_in_large_file({
    filePath: logFile,
    pattern: "(ERROR|FATAL).*database.*(timeout|connection|deadlock)",
    regex: true,
    contextBefore: 5,
    contextAfter: 5,
    maxResults: 20
  });

  console.log(`Found ${errors.totalMatches} database errors\n`);

  // Step 2: Analyze each error
  for (const error of errors.matches) {
    console.log(`=== Error at line ${error.lineNumber} ===`);
    console.log("Error:", error.line);

    // Check context for related information
    const hasRetry = error.contextAfter.some(line =>
      line.includes("retry")
    );
    const hasRecovery = error.contextAfter.some(line =>
      line.includes("recovered") || line.includes("success")
    );

    if (hasRetry) {
      console.log("✓ Retry attempted");
    }
    if (hasRecovery) {
      console.log("✓ Successfully recovered");
    } else {
      console.log("⚠ No recovery detected");
    }

    console.log("\nFull context:");
    console.log(error.contextBefore.join("\n"));
    console.log(">>> " + error.line);
    console.log(error.contextAfter.join("\n"));
    console.log("\n");
  }
}

await investigateDatabaseErrors("/var/log/app.log");

Performance Analysis ​

Identify slow queries and operations:

typescript
async function analyzePerformance(logFile: string) {
  const stream = stream_large_file({
    filePath: logFile,
    chunkSize: 500
  });

  const slowOperations: Array<{
    operation: string;
    duration: number;
    lineNumber: number;
  }> = [];

  let currentLine = 0;

  for await (const chunk of stream) {
    for (const line of chunk.lines) {
      currentLine++;

      // Extract duration: "Query took 1234ms"
      const durationMatch = line.match(/took\s+(\d+)ms/);
      if (durationMatch) {
        const duration = parseInt(durationMatch[1]);

        // Flag operations > 1 second
        if (duration > 1000) {
          // Extract operation name
          const opMatch = line.match(/(\w+)\s+took/);
          const operation = opMatch ? opMatch[1] : "unknown";

          slowOperations.push({
            operation,
            duration,
            lineNumber: currentLine
          });
        }
      }
    }
  }

  // Sort by duration (slowest first)
  slowOperations.sort((a, b) => b.duration - a.duration);

  console.log("Top 10 slowest operations:");
  slowOperations.slice(0, 10).forEach(op => {
    console.log(
      `${op.operation}: ${op.duration}ms (line ${op.lineNumber})`
    );
  });

  // Statistics
  const avgDuration =
    slowOperations.reduce((sum, op) => sum + op.duration, 0) /
    slowOperations.length;

  console.log(`\nTotal slow operations: ${slowOperations.length}`);
  console.log(`Average duration: ${avgDuration.toFixed(0)}ms`);
}

await analyzePerformance("/var/log/app.log");

Security Audit ​

Find failed login attempts and suspicious activity:

typescript
async function securityAudit(authLog: string) {
  console.log("=== Security Audit ===\n");

  // 1. Failed login attempts
  const failedLogins = await search_in_large_file({
    filePath: authLog,
    pattern: "Failed password.*from\\s+(\\d{1,3}\\.){3}\\d{1,3}",
    regex: true,
    contextAfter: 2,
    maxResults: 100
  });

  console.log(`Failed login attempts: ${failedLogins.totalMatches}`);

  // Count by IP
  const ipCounts = new Map<string, number>();
  failedLogins.matches.forEach(match => {
    const ipMatch = match.line.match(/(\d{1,3}\.){3}\d{1,3}/);
    if (ipMatch) {
      const ip = ipMatch[0];
      ipCounts.set(ip, (ipCounts.get(ip) || 0) + 1);
    }
  });

  // Show top offenders
  console.log("\nTop 5 IPs with failed attempts:");
  Array.from(ipCounts.entries())
    .sort(([, a], [, b]) => b - a)
    .slice(0, 5)
    .forEach(([ip, count]) => {
      console.log(`${ip}: ${count} attempts`);
      if (count > 10) {
        console.log(`  ⚠ ALERT: Potential brute force attack`);
      }
    });

  // 2. Privilege escalation attempts
  const sudoAttempts = await search_in_large_file({
    filePath: authLog,
    pattern: "sudo.*COMMAND",
    regex: true,
    contextBefore: 1,
    maxResults: 50
  });

  console.log(`\nSudo commands executed: ${sudoAttempts.totalMatches}`);

  // 3. Root logins
  const rootLogins = await search_in_large_file({
    filePath: authLog,
    pattern: "session opened for user root",
    regex: false,
    contextBefore: 2,
    maxResults: 20
  });

  console.log(`Root login sessions: ${rootLogins.totalMatches}`);
  if (rootLogins.totalMatches > 0) {
    console.log("⚠ WARNING: Direct root logins detected");
  }
}

await securityAudit("/var/log/auth.log");

Real-Time Monitoring ​

Tail Log File ​

Monitor log file for new entries:

typescript
async function tailLog(logFile: string, pattern?: string) {
  // Get current file structure
  let structure = await get_file_structure({
    filePath: logFile
  });

  let lastLine = structure.totalLines;

  console.log(`Monitoring ${logFile} from line ${lastLine}...`);
  console.log("Press Ctrl+C to stop\n");

  // Poll for new lines
  while (true) {
    await sleep(1000); // Check every second

    const newStructure = await get_file_structure({
      filePath: logFile
    });

    if (newStructure.totalLines > lastLine) {
      // Read new lines
      const chunk = await read_large_file_chunk({
        filePath: logFile,
        chunkIndex: Math.floor(lastLine / newStructure.chunkSize)
      });

      // Extract only new lines
      const newLines = chunk.content
        .split("\n")
        .slice(lastLine % newStructure.chunkSize);

      // Filter by pattern if provided
      const filtered = pattern
        ? newLines.filter(line => line.includes(pattern))
        : newLines;

      filtered.forEach(line => {
        console.log(line);
      });

      lastLine = newStructure.totalLines;
    }
  }
}

// Monitor for errors
await tailLog("/var/log/app.log", "ERROR");

Real-Time Alerts ​

Send alerts for critical errors:

typescript
async function monitorWithAlerts(logFile: string) {
  const stream = stream_large_file({
    filePath: logFile,
    chunkSize: 10
  });

  const criticalPatterns = [
    /FATAL/,
    /OutOfMemory/,
    /StackOverflow/,
    /database.*connection.*failed/i,
    /disk.*full/i
  ];

  for await (const chunk of stream) {
    for (const line of chunk.lines) {
      for (const pattern of criticalPatterns) {
        if (pattern.test(line)) {
          console.error("🚨 CRITICAL ALERT:", line);

          // Send notification
          await sendAlert({
            severity: "critical",
            message: line,
            timestamp: new Date()
          });

          // Get more context
          const context = await navigate_to_line({
            filePath: logFile,
            lineNumber: chunk.startLine + chunk.lines.indexOf(line),
            contextLines: 10
          });

          console.log("Context:", context);
        }
      }
    }

    // Brief pause to avoid overwhelming
    await sleep(100);
  }
}

Statistical Analysis ​

Log Volume Analysis ​

Analyze log volume over time:

typescript
async function analyzeLogVolume(logFile: string) {
  const stream = stream_large_file({
    filePath: logFile,
    chunkSize: 5000
  });

  const volumeByHour = new Map<string, number>();
  const levelCounts = {
    DEBUG: 0,
    INFO: 0,
    WARN: 0,
    ERROR: 0,
    FATAL: 0
  };

  for await (const chunk of stream) {
    for (const line of chunk.lines) {
      // Extract timestamp hour
      const timeMatch = line.match(/(\d{4}-\d{2}-\d{2}\s+\d{2}):/);
      if (timeMatch) {
        const hour = timeMatch[1];
        volumeByHour.set(hour, (volumeByHour.get(hour) || 0) + 1);
      }

      // Count by level
      for (const level of Object.keys(levelCounts)) {
        if (line.includes(level)) {
          levelCounts[level]++;
          break;
        }
      }
    }
  }

  // Display results
  console.log("=== Log Volume Analysis ===\n");

  console.log("Volume by hour:");
  Array.from(volumeByHour.entries())
    .sort(([a], [b]) => a.localeCompare(b))
    .forEach(([hour, count]) => {
      const bar = "█".repeat(Math.ceil(count / 100));
      console.log(`${hour}:00 | ${bar} ${count}`);
    });

  console.log("\nLog levels:");
  Object.entries(levelCounts).forEach(([level, count]) => {
    const total = Object.values(levelCounts).reduce((a, b) => a + b, 0);
    const percent = ((count / total) * 100).toFixed(1);
    console.log(`${level}: ${count} (${percent}%)`);
  });

  // Find peak hour
  const peakHour = Array.from(volumeByHour.entries()).reduce((max, entry) =>
    entry[1] > max[1] ? entry : max
  );

  console.log(`\nPeak activity: ${peakHour[0]}:00 (${peakHour[1]} logs)`);
}

await analyzeLogVolume("/var/log/app.log");

Response Time Analysis ​

Analyze API response times:

typescript
async function analyzeResponseTimes(logFile: string) {
  const stream = stream_large_file({
    filePath: logFile,
    chunkSize: 1000
  });

  const responseTimes: number[] = [];
  const endpointTimes = new Map<string, number[]>();

  for await (const chunk of stream) {
    for (const line of chunk.lines) {
      // Extract: "GET /api/users took 123ms"
      const match = line.match(/(GET|POST|PUT|DELETE)\s+(\/\S+).*?(\d+)ms/);
      if (match) {
        const [, method, endpoint, ms] = match;
        const time = parseInt(ms);

        responseTimes.push(time);

        const key = `${method} ${endpoint}`;
        if (!endpointTimes.has(key)) {
          endpointTimes.set(key, []);
        }
        endpointTimes.get(key)!.push(time);
      }
    }
  }

  // Calculate percentiles
  const sorted = responseTimes.sort((a, b) => a - b);
  const p50 = sorted[Math.floor(sorted.length * 0.5)];
  const p95 = sorted[Math.floor(sorted.length * 0.95)];
  const p99 = sorted[Math.floor(sorted.length * 0.99)];
  const avg = responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length;

  console.log("=== Response Time Analysis ===\n");
  console.log(`Total requests: ${responseTimes.length}`);
  console.log(`Average: ${avg.toFixed(0)}ms`);
  console.log(`P50: ${p50}ms`);
  console.log(`P95: ${p95}ms`);
  console.log(`P99: ${p99}ms`);

  // Slowest endpoints
  console.log("\nSlowest endpoints (P95):");
  Array.from(endpointTimes.entries())
    .map(([endpoint, times]) => {
      const sorted = times.sort((a, b) => a - b);
      const p95 = sorted[Math.floor(sorted.length * 0.95)];
      return { endpoint, p95, count: times.length };
    })
    .sort((a, b) => b.p95 - a.p95)
    .slice(0, 10)
    .forEach(({ endpoint, p95, count }) => {
      console.log(`${endpoint}: ${p95}ms (${count} requests)`);
    });
}

await analyzeResponseTimes("/var/log/access.log");

Best Practices ​

1. Use Streaming for Large Files ​

For files > 100MB, always use streaming:

typescript
// Good: Streaming approach
async function processLargeLog(logFile: string) {
  const stream = stream_large_file({
    filePath: logFile,
    chunkSize: 1000
  });

  for await (const chunk of stream) {
    await processChunk(chunk.lines);
  }
}

// Bad: Loading entire file
async function processLargeLogBad(logFile: string) {
  const allLines = await readFileSync(logFile, "utf-8").split("\n");
  // OutOfMemoryError for large files!
}

2. Limit Search Results ​

Use maxResults to prevent scanning entire file:

typescript
// Good: Limited search
const errors = await search_in_large_file({
  filePath: logFile,
  pattern: "ERROR",
  maxResults: 100
});

// Bad: Unlimited search (slow for large files)
const allErrors = await search_in_large_file({
  filePath: logFile,
  pattern: "ERROR"
  // Will scan entire file
});

3. Cache File Structure ​

File metadata rarely changes:

typescript
// Cache file structure
let cachedStructure = null;

async function getStructure(logFile: string) {
  if (!cachedStructure) {
    cachedStructure = await get_file_structure({
      filePath: logFile
    });
  }
  return cachedStructure;
}

4. Use Appropriate Context ​

Balance detail vs. performance:

typescript
// Quick scan: minimal context
const quickScan = await search_in_large_file({
  filePath: logFile,
  pattern: "ERROR",
  contextBefore: 1,
  contextAfter: 1
});

// Deep investigation: more context
const deepDive = await search_in_large_file({
  filePath: logFile,
  pattern: "ERROR",
  contextBefore: 10,
  contextAfter: 10,
  maxResults: 5
});

See Also ​

Released under the MIT License.