Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-27 07:41:42

0001 #!/usr/bin/env python3
0002 """
0003 Test script for REST API logging functionality.
0004 
0005 This script demonstrates how agents can send log messages to the swf-monitor
0006 database via the REST API endpoint. It provides both direct REST calls and
0007 a custom logging handler that integrates with Python's logging system.
0008 """
0009 
0010 import requests
0011 import logging
0012 import json
0013 import os
0014 import sys
0015 from datetime import datetime
0016 from typing import Dict, Any, Optional
0017 
0018 
0019 class RestLogHandler(logging.Handler):
0020     """
0021     Custom logging handler that sends log records to the swf-monitor REST API.
0022     
0023     This handler formats Python log records and sends them to the /api/logs/
0024     endpoint for storage in the database.
0025     """
0026     
0027     def __init__(self, base_url: str, app_name: str, instance_name: str, 
0028                  timeout: int = 10):
0029         """
0030         Initialize the REST logging handler.
0031         
0032         Args:
0033             base_url: Base URL of the swf-monitor API (e.g., 'http://localhost:8000')
0034             app_name: Name of the application sending logs
0035             instance_name: Instance identifier for this application
0036             timeout: Request timeout in seconds
0037         """
0038         super().__init__()
0039         self.logs_url = f"{base_url.rstrip('/')}/api/logs/"
0040         self.app_name = app_name
0041         self.instance_name = instance_name
0042         self.timeout = timeout
0043         self.session = requests.Session()
0044         
0045     def emit(self, record: logging.LogRecord) -> None:
0046         """
0047         Send a log record to the REST API.
0048         
0049         Args:
0050             record: Python LogRecord to send
0051         """
0052         try:
0053             log_data = self._format_log_record(record)
0054             response = self.session.post(
0055                 self.logs_url, 
0056                 json=log_data, 
0057                 timeout=self.timeout,
0058                 headers={'Content-Type': 'application/json'}
0059             )
0060             response.raise_for_status()
0061             
0062         except requests.exceptions.RequestException as e:
0063             # Handle network/API errors - print to stderr but don't raise
0064             # to avoid disrupting the application
0065             print(f"Failed to send log to REST API: {e}", file=sys.stderr)
0066         except Exception as e:
0067             # Handle any other errors in log formatting/sending
0068             print(f"Error in REST log handler: {e}", file=sys.stderr)
0069     
0070     def _format_log_record(self, record: logging.LogRecord) -> Dict[str, Any]:
0071         """
0072         Convert a Python LogRecord to the format expected by the REST API.
0073         
0074         Args:
0075             record: Python LogRecord
0076             
0077         Returns:
0078             Dictionary suitable for JSON serialization and REST API
0079         """
0080         return {
0081             'app_name': self.app_name,
0082             'instance_name': self.instance_name,
0083             'timestamp': datetime.fromtimestamp(record.created).isoformat(),
0084             'level': record.levelno,
0085             'levelname': record.levelname,
0086             'message': record.getMessage(),
0087             'module': record.module or 'unknown',
0088             'funcname': record.funcName or 'unknown',
0089             'lineno': record.lineno or 0,
0090             'process': record.process or 0,
0091             'thread': record.thread or 0,
0092             'extra_data': {
0093                 'pathname': record.pathname,
0094                 'filename': record.filename,
0095                 'created': record.created,
0096                 'msecs': record.msecs,
0097             }
0098         }
0099 
0100 
0101 def send_direct_log_message(base_url: str, app_name: str, instance_name: str,
0102                           level: str, message: str, **kwargs) -> bool:
0103     """
0104     Send a log message directly to the REST API without using Python logging.
0105     
0106     Args:
0107         base_url: Base URL of the swf-monitor API
0108         app_name: Application name
0109         instance_name: Instance identifier  
0110         level: Log level (INFO, WARNING, ERROR, etc.)
0111         message: Log message text
0112         **kwargs: Additional fields for the log record
0113         
0114     Returns:
0115         True if successful, False otherwise
0116     """
0117     logs_url = f"{base_url.rstrip('/')}/api/logs/"
0118     
0119     # Map level names to integers
0120     level_mapping = {
0121         'DEBUG': logging.DEBUG,
0122         'INFO': logging.INFO, 
0123         'WARNING': logging.WARNING,
0124         'ERROR': logging.ERROR,
0125         'CRITICAL': logging.CRITICAL
0126     }
0127     
0128     log_data = {
0129         'app_name': app_name,
0130         'instance_name': instance_name,
0131         'timestamp': datetime.now().isoformat(),
0132         'level': level_mapping.get(level.upper(), logging.INFO),
0133         'levelname': level.upper(),
0134         'message': message,
0135         'module': kwargs.get('module', 'test_script'),
0136         'funcname': kwargs.get('funcname', 'send_direct_log_message'),
0137         'lineno': kwargs.get('lineno', 0),
0138         'process': kwargs.get('process', os.getpid()),
0139         'thread': kwargs.get('thread', 0),
0140         'extra_data': kwargs.get('extra_data', {})
0141     }
0142     
0143     try:
0144         response = requests.post(
0145             logs_url,
0146             json=log_data,
0147             timeout=10,
0148             headers={'Content-Type': 'application/json'}
0149         )
0150         response.raise_for_status()
0151         print(f"✅ Successfully sent {level} log: {message}")
0152         return True
0153         
0154     except requests.exceptions.RequestException as e:
0155         print(f"❌ Failed to send log: {e}")
0156         return False
0157 
0158 
0159 def test_rest_logging(base_url: str = "http://localhost:8000") -> None:
0160     """
0161     Comprehensive test of REST API logging functionality.
0162     
0163     Tests both direct REST calls and the custom logging handler.
0164     
0165     Args:
0166         base_url: Base URL of the swf-monitor service
0167     """
0168     app_name = "test_logging_script"
0169     instance_name = f"test_instance_{os.getpid()}"
0170     
0171     print(f"🧪 Testing REST logging against {base_url}")
0172     print(f"📝 App: {app_name}, Instance: {instance_name}")
0173     print("-" * 60)
0174     
0175     # Test 1: Direct REST API calls
0176     print("1️⃣ Testing direct REST API calls...")
0177     
0178     test_messages = [
0179         ("INFO", "Application started successfully"),
0180         ("WARNING", "Configuration file not found, using defaults"),
0181         ("ERROR", "Failed to connect to external service"),
0182         ("DEBUG", "Processing item 42 of 100"),
0183         ("CRITICAL", "System out of memory, shutting down")
0184     ]
0185     
0186     success_count = 0
0187     for level, message in test_messages:
0188         if send_direct_log_message(base_url, app_name, instance_name, level, message):
0189             success_count += 1
0190     
0191     print(f"Direct API calls: {success_count}/{len(test_messages)} successful\n")
0192     
0193     # Test 2: Python logging handler integration
0194     print("2️⃣ Testing Python logging handler integration...")
0195     
0196     # Create logger with REST handler
0197     logger = logging.getLogger('test_rest_logger')
0198     logger.setLevel(logging.DEBUG)
0199     
0200     # Add our custom REST handler
0201     rest_handler = RestLogHandler(base_url, app_name, f"{instance_name}_handler")
0202     logger.addHandler(rest_handler)
0203     
0204     # Send various log levels through Python logging
0205     logger.debug("Debug message from Python logging")
0206     logger.info("Info message with data: %s", {"key": "value"})
0207     logger.warning("Warning about deprecated function")
0208     logger.error("Error processing request ID %d", 12345)
0209     logger.critical("Critical system failure detected")
0210     
0211     print("Python logging handler tests completed\n")
0212     
0213     # Test 3: Bulk logging simulation
0214     print("3️⃣ Testing bulk logging (simulating real agent usage)...")
0215     
0216     for i in range(10):
0217         logger.info(f"Processing workflow step {i+1}/10")
0218         if i % 3 == 0:
0219             logger.debug(f"Step {i+1} details: processing file batch")
0220         if i == 7:
0221             logger.warning(f"Step {i+1} took longer than expected")
0222     
0223     logger.info("Workflow processing completed successfully")
0224     print("Bulk logging simulation completed\n")
0225     
0226     print("✅ All REST logging tests completed!")
0227     print("Check the swf-monitor database/UI to verify log entries were created.")
0228 
0229 
0230 def main():
0231     """Main entry point for the test script."""
0232     import argparse
0233     
0234     parser = argparse.ArgumentParser(
0235         description="Test REST API logging functionality for swf-monitor"
0236     )
0237     parser.add_argument(
0238         '--url', '-u',
0239         default='http://localhost:8000',
0240         help='Base URL of swf-monitor service (default: http://localhost:8000)'
0241     )
0242     parser.add_argument(
0243         '--direct-only',
0244         action='store_true',
0245         help='Only test direct REST calls, skip Python logging handler'
0246     )
0247     
0248     args = parser.parse_args()
0249     
0250     if args.direct_only:
0251         # Quick test of direct API
0252         print("🧪 Quick REST API logging test...")
0253         success = send_direct_log_message(
0254             args.url, 
0255             "quick_test", 
0256             "test_instance",
0257             "INFO", 
0258             "Quick test log message"
0259         )
0260         sys.exit(0 if success else 1)
0261     else:
0262         # Full test suite
0263         test_rest_logging(args.url)
0264 
0265 
0266 if __name__ == "__main__":
0267     main()