Log File Analyzer
Log File Analyzer - Comprehensive Array Operations
A real-world example demonstrating Utah's powerful array handling capabilities through a log file analyzer. This script processes server logs, analyzes patterns, generates reports, and demonstrates most of Utah's array functions in practical scenarios.
🎬 Interactive Demo
Watch this script in action! The demo shows comprehensive array operations including length, isEmpty, contains, merge, unique, sort, shuffle, reverse, and join:
Features Demonstrated
- Dynamic array building from file processing
 - Array filtering and searching with 
array.contains() - Data aggregation using 
array.merge()andarray.unique() - Sorting and organizing with 
array.sort() - Statistical analysis using array manipulation
 - Report generation with 
array.join() - Error handling with array validation
 - Interactive menus using arrays
 - File system integration with arrays
 
Complete Script: log_analyzer.shx
#!/usr/bin/env utah
// Log File Analyzer - Comprehensive Array Operations Demo
// Processes server logs and generates detailed reports
function main(): void {
  console.log("🔍 Utah Log File Analyzer");
  console.log("=========================");
  // Initialize data structures
  let logFiles: string[] = [
    "/var/log/apache2/access.log",
    "/var/log/nginx/access.log",
    "/var/log/app/application.log"
  ];
  let allLogEntries: string[] = [];
  let errorEntries: string[] = [];
  let warningEntries: string[] = [];
  let ipAddresses: string[] = [];
  let userAgents: string[] = [];
  // For demo purposes, use sample data
  console.log("Using sample data for demonstration...");
  createSampleData(allLogEntries, errorEntries, warningEntries, ipAddresses);
  // Generate comprehensive report
  generateReport(allLogEntries, errorEntries, warningEntries, ipAddresses, userAgents);
  // Interactive analysis menu
  showAnalysisMenu(allLogEntries, errorEntries, warningEntries, ipAddresses);
}
function createSampleData(
  allEntries: string[],
  errors: string[],
  warnings: string[],
  ips: string[]
): void {
  // Sample log entries
  let sampleLogs: string[] = [
    "2024-01-15 10:30:45 [INFO] User login successful - IP: 192.168.1.100",
    "2024-01-15 10:31:12 [ERROR] Database connection failed - timeout after 30s",
    "2024-01-15 10:31:45 [WARN] High memory usage detected - 85% utilization",
    "2024-01-15 10:32:01 [INFO] File upload completed - size: 2.5MB",
    "2024-01-15 10:32:30 [ERROR] 404 Not Found - /api/missing-endpoint",
    "2024-01-15 10:33:15 [INFO] Cache refresh completed - 1500 entries updated",
    "2024-01-15 10:33:45 [WARN] Slow query detected - execution time: 2.3s",
    "2024-01-15 10:34:12 [ERROR] Connection timeout - host unreachable"
  ];
  // Process sample data
  for (let log: string in sampleLogs) {
    array.push(allEntries, log);
    // Categorize by log level
    if (string.contains(log, "ERROR")) {
      array.push(errors, log);
    } else if (string.contains(log, "WARN")) {
      array.push(warnings, log);
    }
    // Extract sample IP addresses
    if (string.contains(log, "192.168.1.100")) {
      if (!array.contains(ips, "192.168.1.100")) {
        array.push(ips, "192.168.1.100");
      }
    }
  }
  // Add more sample IPs for demonstration
  array.push(ips, "203.0.113.45");
  array.push(ips, "198.51.100.78");
  array.push(ips, "10.0.0.15");
}
function generateReport(
  allEntries: string[],
  errors: string[],
  warnings: string[],
  ips: string[],
  agents: string[]
): void {
  console.log("📋 COMPREHENSIVE LOG ANALYSIS REPORT");
  console.log("=====================================");
  // Basic statistics using array.length()
  let totalEntries: number = array.length(allEntries);
  let errorCount: number = array.length(errors);
  let warningCount: number = array.length(warnings);
  let ipCount: number = array.length(ips);
  console.log("📊 Log Entry Statistics:");
  console.log("Total entries processed:");
  console.log(totalEntries);
  console.log("Error entries found:");
  console.log(errorCount);
  console.log("Warning entries found:");
  console.log(warningCount);
  console.log("Unique IP addresses:");
  console.log(ipCount);
  // Error analysis
  let errorsEmpty: boolean = array.isEmpty(errors);
  if (!errorsEmpty) {
    console.log("🚨 Error Analysis:");
    analyzeErrors(errors);
  }
  // Warning analysis
  let warningsEmpty: boolean = array.isEmpty(warnings);
  if (!warningsEmpty) {
    console.log("⚠️  Warning Analysis:");
    analyzeWarnings(warnings);
  }
  // IP address analysis
  let ipsEmpty: boolean = array.isEmpty(ips);
  if (!ipsEmpty) {
    console.log("🌐 IP Address Analysis:");
    analyzeIPAddresses(ips);
  }
}
function analyzeErrors(errors: string[]): void {
  // Count error types
  let errorTypes: string[] = [];
  let errorCounts: number[] = [];
  for (let error: string in errors) {
    let errorType: string = extractErrorType(error);
    let index: number = findOrAddErrorType(errorTypes, errorCounts, errorType);
    errorCounts[index] = errorCounts[index] + 1;
  }
  // Display error types
  console.log("Error type breakdown:");
  let typeCount: number = array.length(errorTypes);
  for (let i: number = 0; i < typeCount; i++) {
    let type: string = errorTypes[i];
    let count: number = errorCounts[i];
    console.log(type);
    console.log("occurrences:");
    console.log(count);
  }
}
function extractErrorType(errorLine: string): string {
  // Extract error type from log line (simplified)
  if (string.contains(errorLine, "404")) return "404 Not Found";
  if (string.contains(errorLine, "500")) return "500 Internal Server Error";
  if (string.contains(errorLine, "timeout")) return "Timeout Error";
  if (string.contains(errorLine, "connection")) return "Connection Error";
  return "Other Error";
}
function findOrAddErrorType(types: string[], counts: number[], errorType: string): number {
  let typeCount: number = array.length(types);
  for (let i: number = 0; i < typeCount; i++) {
    if (types[i] == errorType) {
      return i;
    }
  }
  // Not found, add new type
  array.push(types, errorType);
  array.push(counts, 0);
  let newLength: number = array.length(types);
  return newLength - 1;
}
function analyzeWarnings(warnings: string[]): void {
  let warningCount: number = array.length(warnings);
  let displayCount: number = warningCount > 3 ? 3 : warningCount;
  console.log("Recent warnings:");
  for (let i: number = warningCount - displayCount; i < warningCount; i++) {
    let warning: string = warnings[i];
    console.log(warning);
  }
}
function analyzeIPAddresses(ips: string[]): void {
  // Sort IPs for better readability using array.sort()
  let sortedIPs: string[] = array.sort(ips);
  let ipCount: number = array.length(sortedIPs);
  console.log("Found unique IP addresses:");
  console.log(ipCount);
  // Categorize by type
  let internalIPs: string[] = [];
  let externalIPs: string[] = [];
  for (let ip: string in sortedIPs) {
    if (string.startsWith(ip, "192.168.") ||
        string.startsWith(ip, "10.") ||
        string.startsWith(ip, "172.")) {
      array.push(internalIPs, ip);
    } else {
      array.push(externalIPs, ip);
    }
  }
  let internalCount: number = array.length(internalIPs);
  let externalCount: number = array.length(externalIPs);
  console.log("Internal IPs:");
  console.log(internalCount);
  console.log("External IPs:");
  console.log(externalCount);
  // Show sample external IPs using array.join()
  let extEmpty: boolean = array.isEmpty(externalIPs);
  if (!extEmpty) {
    let sampleCount: number = externalCount > 3 ? 3 : externalCount;
    console.log("Sample external IPs:");
    for (let i: number = 0; i < sampleCount; i++) {
      console.log(externalIPs[i]);
    }
  }
}
function showAnalysisMenu(
  allEntries: string[],
  errors: string[],
  warnings: string[],
  ips: string[]
): void {
  console.log("🎯 INTERACTIVE ANALYSIS MENU");
  console.log("=============================");
  let menuOptions: string[] = [
    "Show detailed error analysis",
    "Export IP addresses to file",
    "Search log entries by keyword",
    "Generate summary report",
    "Show array statistics",
    "Exit"
  ];
  console.log("Available options:");
  let optionCount: number = array.length(menuOptions);
  for (let i: number = 0; i < optionCount; i++) {
    let option: string = menuOptions[i];
    let menuNumber: number = i + 1;
    console.log(menuNumber);
    console.log(". ");
    console.log(option);
  }
  // For demo purposes, we'll simulate selecting option 5 (array statistics)
  let choice: number = 5;
  let selectedOption: string = menuOptions[choice - 1];
  console.log("Selected option:");
  console.log(choice);
  console.log(selectedOption);
  if (choice == 5) {
    showArrayStatistics(allEntries, errors, warnings, ips);
  }
}
function showArrayStatistics(
  allEntries: string[],
  errors: string[],
  warnings: string[],
  ips: string[]
): void {
  console.log("📈 ARRAY OPERATIONS STATISTICS");
  console.log("===============================");
  // Demonstrate array functions
  console.log("Array function demonstrations:");
  // array.length() demonstrations
  let totalCount: number = array.length(allEntries);
  let errorCount: number = array.length(errors);
  let warningCount: number = array.length(warnings);
  let ipCount: number = array.length(ips);
  console.log("🔢 array.length() results:");
  console.log("All entries:");
  console.log(totalCount);
  console.log("Errors:");
  console.log(errorCount);
  console.log("Warnings:");
  console.log(warningCount);
  console.log("IPs:");
  console.log(ipCount);
  // array.isEmpty() demonstrations
  let errorsEmpty: boolean = array.isEmpty(errors);
  let warningsEmpty: boolean = array.isEmpty(warnings);
  let ipsEmpty: boolean = array.isEmpty(ips);
  console.log("❓ array.isEmpty() results:");
  console.log("Errors empty:");
  console.log(errorsEmpty);
  console.log("Warnings empty:");
  console.log(warningsEmpty);
  console.log("IPs empty:");
  console.log(ipsEmpty);
  // array.contains() demonstrations
  if (!ipsEmpty) {
    let firstIP: string = ips[0];
    let hasFirstIP: boolean = array.contains(ips, firstIP);
    let hasFakeIP: boolean = array.contains(ips, "999.999.999.999");
    console.log("🔍 array.contains() examples:");
    console.log("IPs contains first IP:");
    console.log(hasFirstIP);
    console.log("IPs contains fake IP:");
    console.log(hasFakeIP);
  }
  // array.merge() demonstration
  let sampleErrors: string[] = ["Error 1", "Error 2"];
  let sampleWarnings: string[] = ["Warning 1", "Warning 2"];
  let combined: string[] = array.merge(sampleErrors, sampleWarnings);
  let sampleErrorCount: number = array.length(sampleErrors);
  let sampleWarningCount: number = array.length(sampleWarnings);
  let combinedCount: number = array.length(combined);
  console.log("🔗 array.merge() example:");
  console.log("Merged");
  console.log(sampleErrorCount);
  console.log("errors +");
  console.log(sampleWarningCount);
  console.log("warnings =");
  console.log(combinedCount);
  console.log("items");
  // array.unique() demonstration
  let duplicatedList: string[] = ["item1", "item2", "item1", "item3", "item2"];
  let uniqueList: string[] = array.unique(duplicatedList);
  let originalCount: number = array.length(duplicatedList);
  let uniqueCount: number = array.length(uniqueList);
  console.log("⭐ array.unique() example:");
  console.log("Original:");
  console.log(originalCount);
  console.log("items, Unique:");
  console.log(uniqueCount);
  console.log("items");
  // array.sort() demonstration
  let unsortedNumbers: string[] = ["3", "1", "4", "1", "5"];
  let sortedNumbers: string[] = array.sort(unsortedNumbers);
  let unsortedList: string = array.join(unsortedNumbers, ", ");
  let sortedList: string = array.join(sortedNumbers, ", ");
  console.log("📊 array.sort() example:");
  console.log("Unsorted:");
  console.log(unsortedList);
  console.log("Sorted:");
  console.log(sortedList);
  // array.shuffle() demonstration
  let orderedList: string[] = ["A", "B", "C", "D", "E"];
  let shuffledList: string[] = array.shuffle(orderedList);
  let orderedJoined: string = array.join(orderedList, ", ");
  let shuffledJoined: string = array.join(shuffledList, ", ");
  console.log("🎲 array.shuffle() example:");
  console.log("Original:");
  console.log(orderedJoined);
  console.log("Shuffled:");
  console.log(shuffledJoined);
  // array.reverse() demonstration
  let normalOrder: string[] = ["first", "second", "third"];
  let reversedOrder: string[] = array.reverse(normalOrder);
  let normalJoined: string = array.join(normalOrder, " → ");
  let reversedJoined: string = array.join(reversedOrder, " ← ");
  console.log("🔄 array.reverse() example:");
  console.log("Normal:");
  console.log(normalJoined);
  console.log("Reversed:");
  console.log(reversedJoined);
  // array.join() demonstrations
  console.log("🔗 array.join() examples:");
  let fruits: string[] = ["apple", "banana", "cherry"];
  let commaSeparated: string = array.join(fruits, ", ");
  let pipeSeparated: string = array.join(fruits, " | ");
  let spaceSeparated: string = array.join(fruits, " ");
  console.log("Comma-separated:");
  console.log(commaSeparated);
  console.log("Pipe-separated:");
  console.log(pipeSeparated);
  console.log("Space-separated:");
  console.log(spaceSeparated);
}
// Run the main function
main();
Quick Reference: Array Functions Used
This comprehensive example demonstrates all of Utah's array functions:
| Function | Purpose | Example Usage | 
|---|---|---|
array.length(arr) | Get array size | array.length(logEntries) | 
array.isEmpty(arr) | Check if empty | array.isEmpty(errors) | 
array.contains(arr, item) | Search for item | array.contains(ips, "192.168.1.1") | 
array.push(arr, item) | Add to end | array.push(errors, errorMsg) | 
array.merge(arr1, arr2) | Combine arrays | array.merge(errors, warnings) | 
array.unique(arr) | Remove duplicates | array.unique(ipAddresses) | 
array.sort(arr) | Sort alphabetically | array.sort(usernames) | 
array.shuffle(arr) | Randomize order | array.shuffle(sampleData) | 
array.reverse(arr) | Reverse order | array.reverse(chronological) | 
array.join(arr, sep) | Convert to string | array.join(items, ", ") | 
Usage Examples
Running the Log Analyzer
# Compile the script
utah compile log_analyzer.shx
# Run with your log files
./log_analyzer.sh
# Or run directly
utah run log_analyzer.shx
Expected Output
🔍 Utah Log File Analyzer
=========================
Using sample data for demonstration...
📋 COMPREHENSIVE LOG ANALYSIS REPORT
=====================================
📊 Log Entry Statistics:
Total entries processed:
8
Error entries found:
3
Warning entries found:
2
Unique IP addresses:
4
🚨 Error Analysis:
Error type breakdown:
Timeout Error
occurrences:
2
404 Not Found
occurrences:
1
⚠️  Warning Analysis:
Recent warnings:
2024-01-15 10:31:45 [WARN] High memory usage detected - 85% utilization
2024-01-15 10:33:45 [WARN] Slow query detected - execution time: 2.3s
🌐 IP Address Analysis:
Found unique IP addresses:
4
Internal IPs:
2
External IPs:
2
Sample external IPs:
198.51.100.78
203.0.113.45
🎯 INTERACTIVE ANALYSIS MENU
=============================
Available options:
1
.
Show detailed error analysis
2
.
Export IP addresses to file
[...continues...]
Key Array Concepts in Utah
Strongly Typed Arrays
Utah enforces type safety for arrays, preventing runtime errors:
let numbers: number[] = [1, 2, 3, 4, 5];      // Numbers only
let names: string[] = ["Alice", "Bob"];        // Strings only
let flags: boolean[] = [true, false, true];    // Booleans only
Dynamic Array Building
Arrays can be built dynamically during script execution:
let logEntries: string[] = [];                 // Start empty
array.push(logEntries, "First entry");         // Add entries
array.push(logEntries, "Second entry");        // Build gradually
Array Iteration Patterns
Utah provides clean iteration syntax:
// For-in loop (recommended)
for (let entry: string in logEntries) {
  console.log("Processing:");
  console.log(entry);
}
// Index-based loop
let entryCount: number = array.length(logEntries);
for (let i: number = 0; i < entryCount; i++) {
  let entry: string = logEntries[i];
  console.log("Entry");
  console.log(i);
  console.log(":");
  console.log(entry);
}
Integration with Other Utah Features
Arrays work seamlessly with Utah's other features:
// File system integration
let configFiles: string[] = ["/etc/app.conf", "/etc/db.conf"];
for (let file: string in configFiles) {
  if (fs.exists(file)) {
    let content: string = fs.readFile(file);
    // Process content...
  }
}
// String processing
let csvData: string = "user1,user2,user3";
let users: string[] = string.split(csvData, ",");
// Console interaction
for (let user: string in users) {
  console.log("Processing user:");
  console.log(user);
}
Advanced Array Patterns Demonstrated
1. Data Aggregation Pattern
// Collect data from multiple sources
let allData: string[] = [];
let sources: string[] = ["source1.log", "source2.log", "source3.log"];
for (let source: string in sources) {
  let sourceData: string[] = processSource(source);
  allData = array.merge(allData, sourceData);
}
2. Classification Pattern
// Classify items into categories
let errors: string[] = [];
let warnings: string[] = [];
let info: string[] = [];
for (let entry: string in allEntries) {
  if (string.contains(entry, "ERROR")) {
    array.push(errors, entry);
  } else if (string.contains(entry, "WARN")) {
    array.push(warnings, entry);
  } else {
    array.push(info, entry);
  }
}
3. Deduplication Pattern
// Remove duplicates from combined data
let rawIPs: string[] = [];
// ... collect IPs from various sources ...
let uniqueIPs: string[] = array.unique(rawIPs);
4. Analysis Pattern
// Analyze and report on data
let sortedData: string[] = array.sort(uniqueIPs);
let report: string = array.join(sortedData, "\n");
console.log("Sorted unique IPs:");
console.log(report);
5. Menu/Selection Pattern
// Interactive menus using arrays
let options: string[] = [
  "View errors",
  "Export data",
  "Generate report",
  "Exit"
];
let optionCount: number = array.length(options);
for (let i: number = 0; i < optionCount; i++) {
  let menuNumber: number = i + 1;
  console.log(menuNumber);
  console.log(". ");
  console.log(options[i]);
}
Benefits Over Traditional Bash Arrays
Utah Arrays (Type-Safe and Intuitive)
let servers: string[] = ["web01", "web02", "db01"];
let serverCount: number = array.length(servers);
console.log("Server count:");
console.log(serverCount);
let hasWeb01: boolean = array.contains(servers, "web01");
if (hasWeb01) {
  console.log("Web01 is configured");
}
let allServers: string[] = array.merge(servers, backupServers);
Bash Arrays (Complex and Error-Prone)
servers=("web01" "web02" "db01")
echo "Server count: ${#servers[@]}"
# Complex contains check
if [[ " ${servers[@]} " =~ " web01 " ]]; then
  echo "Web01 is configured"
fi
# Complex merge
allServers=("${servers[@]}" "${backupServers[@]}")
Key Advantages
- Type Safety: Compile-time type checking prevents errors
 - Intuitive Syntax: Clear, readable array operations
 - Built-in Functions: Rich set of array manipulation methods
 - Error Prevention: Bounds checking and validation
 - Better Performance: Optimized implementations
 - Consistent API: All array functions follow same patterns
 
Real-World Applications
This log analyzer pattern can be adapted for many scenarios:
- System Monitoring: Process system logs and metrics
 - Data Processing: Parse CSV files, API responses
 - Configuration Management: Handle multiple config files
 - Reporting: Generate summaries from multiple sources
 - File Processing: Batch process multiple files
 - User Management: Handle user lists and permissions
 
Related Examples
- Log Analytics Pipeline - Comprehensive string processing and loops example
 - System Health Monitor - Arrays in monitoring
 - Log Analytics Pipeline - Comprehensive string processing and loops example
 
Extension Ideas
You can extend this example to include:
- Database integration with array-based queries
 - Network monitoring with IP address arrays
 - Performance metrics collection
 - Automated alerting based on array analysis
 - Export functionality to multiple formats
 - Interactive filtering and searching
 - Real-time log monitoring with arrays