pyeztrace 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Jefferson Nelsson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,248 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyeztrace
3
+ Version: 0.0.1
4
+ Summary: A powerful, lightweight Python tracing and logging library
5
+ Author: Jefferson Nelsson
6
+ Author-email: Jefferson Nelsson <jefferson.nelsson@gmail.com>
7
+ License-Expression: MIT
8
+ Keywords: logging,tracing,monitoring,debugging,performance
9
+ Classifier: Programming Language :: Python
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.7
12
+ Classifier: Programming Language :: Python :: 3.8
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: Implementation :: CPython
17
+ Classifier: Operating System :: OS Independent
18
+ Requires-Python: >=3.7
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: pydantic-core>=2.33.2
22
+ Requires-Dist: pydantic-settings>=2.9.1
23
+ Dynamic: author
24
+ Dynamic: license-file
25
+ Dynamic: requires-python
26
+
27
+ # PyEzTrace
28
+
29
+ A powerful, lightweight Python tracing and logging library with hierarchical logging, context management, and performance metrics.
30
+
31
+ **Note:** This was a fun, 3 hour experiment for one of my local projects. I'm happy to continue building this out if the community finds it useful and thinks it's a good idea!
32
+
33
+ ## Features
34
+
35
+ - 🌳 **Hierarchical Logging**: Visualize nested operations with tree-style output
36
+ - 🎨 **Multiple Formats**: Support for color, plain text, JSON, CSV, and logfmt outputs
37
+ - 📊 **Performance Metrics**: Built-in timing and tracing capabilities
38
+ - 🔄 **Context Management**: Thread-safe context propagation
39
+ - 🔄 **Log Rotation**: Automatic log file management
40
+ - 🎯 **Decorator-based Tracing**: Easy function and method tracing
41
+ - 💪 **Thread-Safe**: Fully thread-safe implementation
42
+ - 🚀 **High Performance**: Buffered logging and optimized output
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ pip install pyeztrace
48
+ ```
49
+
50
+ ## Quick Start
51
+
52
+ ```python
53
+ from pyeztrace.setup import Setup
54
+ Setup.initialize("MyApp") # Setup First! Make sure you initialize (optional) with your App Name before importing other modules. Default: EZTRACE
55
+
56
+ from pyeztrace.tracer import trace
57
+ from pyeztrace.custom_logging import Logging
58
+
59
+ # Initialize the logging system
60
+ log = Logging(log_format="color") # or "json", "plain", "csv", "logfmt"
61
+
62
+ # Use the tracer decorator
63
+ @trace()
64
+ def process_order(order_id):
65
+ with log.with_context(order_id=order_id):
66
+ log.log_info("Processing order")
67
+ validate_order(order_id)
68
+ process_payment(order_id)
69
+ log.log_info("Order processed successfully")
70
+
71
+ @trace()
72
+ def validate_order(order_id):
73
+ log.log_info("Validating order")
74
+ # Your validation logic here
75
+ ```
76
+
77
+ Output example:
78
+ ```
79
+ 2025-05-13T10:00:00 - INFO - [MyApp] ├── process_order called...
80
+ 2025-05-13T10:00:00 - INFO - [MyApp] ├── Processing order Data: {order_id: "123"}
81
+ 2025-05-13T10:00:00 - INFO - [MyApp] ├────── validate_order called...
82
+ 2025-05-13T10:00:00 - INFO - [MyApp] ├────── Validating order
83
+ 2025-05-13T10:00:00 - INFO - [MyApp] ├────── validate_order Ok. (took 0.50010 seconds)
84
+ 2025-05-13T10:00:01 - INFO - [MyApp] ├── Order processed successfully
85
+ 2025-05-13T10:00:01 - INFO - [MyApp] ├── process_order Ok. (took 1.23456 seconds)
86
+ ```
87
+
88
+ ## Features
89
+
90
+ ### 1. Tracing with Fine-grained Control
91
+
92
+ ```python
93
+ @trace(
94
+ message="Custom trace message", # Optional custom message
95
+ stack=True, # Include stack trace on errors
96
+ modules_or_classes=[my_module], # Trace specific modules
97
+ include=["specific_function_*"], # Include only specific functions
98
+ exclude=["ignored_function_*"] # Exclude specific functions
99
+ )
100
+ """
101
+ Decorator for parent function. Enables tracing for all child functions in the given modules or classes.
102
+ If modules_or_classes is None, it will automatically patch the module where the parent function is defined.
103
+ Accepts a single module/class or a list of modules/classes for cross-module tracing.
104
+ Handles both sync and async parent functions.
105
+ Supports selective tracing via include/exclude patterns (function names).
106
+ """
107
+ def function():
108
+ # Your code here
109
+ pass
110
+ ```
111
+
112
+ ### 2. Context Management
113
+
114
+ Thread-safe context propagation for structured logging:
115
+
116
+ ```python
117
+ with log.with_context(user_id="123", action="login"):
118
+ log.log_info("User logged in") # Will include context automatically
119
+
120
+ with log.with_context(session="abc"):
121
+ # Nested context, inherits parent context
122
+ log.log_info("Session started") # Includes both user_id and session
123
+ ```
124
+
125
+ ### 3. Multiple Output Formats
126
+
127
+ ```python
128
+ # Color-coded console output with hierarchical visualization
129
+ log = Logging(log_format="color")
130
+
131
+ # JSON format for machine processing
132
+ log = Logging(log_format="json")
133
+ # Output: {"timestamp": "2025-05-13T10:00:00", "level": "INFO", "message": "Log message", "data": {"context": "value"}}
134
+
135
+ # Plain text for simple logging
136
+ log = Logging(log_format="plain")
137
+
138
+ # CSV format for spreadsheet analysis
139
+ log = Logging(log_format="csv")
140
+
141
+ # logfmt for system logging
142
+ log = Logging(log_format="logfmt")
143
+ # Output: time=2025-05-13T10:00:00 level=INFO message="Log message" data.context=value
144
+ ```
145
+
146
+ ### 4. Async Support
147
+
148
+ ```python
149
+ @trace()
150
+ async def async_function():
151
+ await some_async_task()
152
+ log.log_info("Async operation completed")
153
+ ```
154
+
155
+ ### 5. Performance Metrics
156
+
157
+ Automatic performance tracking is enabled with `show_metrics=True`:
158
+
159
+ ```python
160
+ Setup.initialize("MyApp", show_metrics=True)
161
+
162
+ @trace()
163
+ def monitored_function():
164
+ # Function execution time will be automatically logged
165
+ pass
166
+
167
+ # At program exit, prints performance summary:
168
+ # === Tracing Performance Metrics Summary ===
169
+ # Function Calls Total(s) Avg(s)
170
+ # --------------------------------------------------------------------
171
+ # my_module.monitored_function 10 1.23456 0.12346
172
+ ```
173
+
174
+ ### 6. Log Rotation
175
+
176
+ Configure automatic log rotation based on file size:
177
+
178
+ ```python
179
+ from pyeztrace.config import config
180
+
181
+ config.max_size = 10 * 1024 * 1024 # 10MB
182
+ config.backup_count = 5 # Keep 5 backup files
183
+ config.log_dir = "logs" # Custom log directory
184
+ config.log_file = "app.log" # Custom log filename
185
+ ```
186
+
187
+ ### 7. Error Handling and Debug Support
188
+
189
+ ```python
190
+ # Different log levels
191
+ log.log_debug("Debug information")
192
+ log.log_info("Normal operation")
193
+ log.log_warning("Warning message")
194
+ log.log_error("Error occurred")
195
+
196
+ try:
197
+ # Your code
198
+ except Exception as e:
199
+ # Automatically log exception with stack trace
200
+ log.raise_exception_to_log(e, "Custom error message", stack=True)
201
+ ```
202
+
203
+ ### 8. Thread-Safe High-Volume Logging
204
+
205
+ The logging system is designed for high-volume scenarios with thread-safe implementation:
206
+
207
+ ```python
208
+ from concurrent.futures import ThreadPoolExecutor
209
+
210
+ @trace()
211
+ def concurrent_operation(worker_id):
212
+ with log.with_context(worker_id=worker_id):
213
+ log.log_info("Worker started")
214
+ # ... work ...
215
+ log.log_info("Worker finished")
216
+
217
+ with ThreadPoolExecutor(max_workers=5) as executor:
218
+ executor.map(concurrent_operation, range(5))
219
+ ```
220
+
221
+ ## Configuration
222
+
223
+ All configuration options can be set via environment variables or code:
224
+
225
+ ```python
226
+ # Via environment variables
227
+ export EZTRACE_LOG_FORMAT="json"
228
+ export EZTRACE_LOG_LEVEL="DEBUG"
229
+ export EZTRACE_LOG_FILE="custom.log"
230
+ export EZTRACE_MAX_SIZE="10485760" # 10MB
231
+ export EZTRACE_BACKUP_COUNT="5"
232
+
233
+ # Via code
234
+ from pyeztrace.config import config
235
+ config.format = "json"
236
+ config.log_level = "DEBUG"
237
+ config.log_file = "custom.log"
238
+ config.max_size = 10 * 1024 * 1024 # 10MB
239
+ config.backup_count = 5
240
+ ```
241
+
242
+ ## Contributing
243
+
244
+ Contributions are welcome! Please read our [Contributing Guidelines](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
245
+
246
+ ## License
247
+
248
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,222 @@
1
+ # PyEzTrace
2
+
3
+ A powerful, lightweight Python tracing and logging library with hierarchical logging, context management, and performance metrics.
4
+
5
+ **Note:** This was a fun, 3 hour experiment for one of my local projects. I'm happy to continue building this out if the community finds it useful and thinks it's a good idea!
6
+
7
+ ## Features
8
+
9
+ - 🌳 **Hierarchical Logging**: Visualize nested operations with tree-style output
10
+ - 🎨 **Multiple Formats**: Support for color, plain text, JSON, CSV, and logfmt outputs
11
+ - 📊 **Performance Metrics**: Built-in timing and tracing capabilities
12
+ - 🔄 **Context Management**: Thread-safe context propagation
13
+ - 🔄 **Log Rotation**: Automatic log file management
14
+ - 🎯 **Decorator-based Tracing**: Easy function and method tracing
15
+ - 💪 **Thread-Safe**: Fully thread-safe implementation
16
+ - 🚀 **High Performance**: Buffered logging and optimized output
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install pyeztrace
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ```python
27
+ from pyeztrace.setup import Setup
28
+ Setup.initialize("MyApp") # Setup First! Make sure you initialize (optional) with your App Name before importing other modules. Default: EZTRACE
29
+
30
+ from pyeztrace.tracer import trace
31
+ from pyeztrace.custom_logging import Logging
32
+
33
+ # Initialize the logging system
34
+ log = Logging(log_format="color") # or "json", "plain", "csv", "logfmt"
35
+
36
+ # Use the tracer decorator
37
+ @trace()
38
+ def process_order(order_id):
39
+ with log.with_context(order_id=order_id):
40
+ log.log_info("Processing order")
41
+ validate_order(order_id)
42
+ process_payment(order_id)
43
+ log.log_info("Order processed successfully")
44
+
45
+ @trace()
46
+ def validate_order(order_id):
47
+ log.log_info("Validating order")
48
+ # Your validation logic here
49
+ ```
50
+
51
+ Output example:
52
+ ```
53
+ 2025-05-13T10:00:00 - INFO - [MyApp] ├── process_order called...
54
+ 2025-05-13T10:00:00 - INFO - [MyApp] ├── Processing order Data: {order_id: "123"}
55
+ 2025-05-13T10:00:00 - INFO - [MyApp] ├────── validate_order called...
56
+ 2025-05-13T10:00:00 - INFO - [MyApp] ├────── Validating order
57
+ 2025-05-13T10:00:00 - INFO - [MyApp] ├────── validate_order Ok. (took 0.50010 seconds)
58
+ 2025-05-13T10:00:01 - INFO - [MyApp] ├── Order processed successfully
59
+ 2025-05-13T10:00:01 - INFO - [MyApp] ├── process_order Ok. (took 1.23456 seconds)
60
+ ```
61
+
62
+ ## Features
63
+
64
+ ### 1. Tracing with Fine-grained Control
65
+
66
+ ```python
67
+ @trace(
68
+ message="Custom trace message", # Optional custom message
69
+ stack=True, # Include stack trace on errors
70
+ modules_or_classes=[my_module], # Trace specific modules
71
+ include=["specific_function_*"], # Include only specific functions
72
+ exclude=["ignored_function_*"] # Exclude specific functions
73
+ )
74
+ """
75
+ Decorator for parent function. Enables tracing for all child functions in the given modules or classes.
76
+ If modules_or_classes is None, it will automatically patch the module where the parent function is defined.
77
+ Accepts a single module/class or a list of modules/classes for cross-module tracing.
78
+ Handles both sync and async parent functions.
79
+ Supports selective tracing via include/exclude patterns (function names).
80
+ """
81
+ def function():
82
+ # Your code here
83
+ pass
84
+ ```
85
+
86
+ ### 2. Context Management
87
+
88
+ Thread-safe context propagation for structured logging:
89
+
90
+ ```python
91
+ with log.with_context(user_id="123", action="login"):
92
+ log.log_info("User logged in") # Will include context automatically
93
+
94
+ with log.with_context(session="abc"):
95
+ # Nested context, inherits parent context
96
+ log.log_info("Session started") # Includes both user_id and session
97
+ ```
98
+
99
+ ### 3. Multiple Output Formats
100
+
101
+ ```python
102
+ # Color-coded console output with hierarchical visualization
103
+ log = Logging(log_format="color")
104
+
105
+ # JSON format for machine processing
106
+ log = Logging(log_format="json")
107
+ # Output: {"timestamp": "2025-05-13T10:00:00", "level": "INFO", "message": "Log message", "data": {"context": "value"}}
108
+
109
+ # Plain text for simple logging
110
+ log = Logging(log_format="plain")
111
+
112
+ # CSV format for spreadsheet analysis
113
+ log = Logging(log_format="csv")
114
+
115
+ # logfmt for system logging
116
+ log = Logging(log_format="logfmt")
117
+ # Output: time=2025-05-13T10:00:00 level=INFO message="Log message" data.context=value
118
+ ```
119
+
120
+ ### 4. Async Support
121
+
122
+ ```python
123
+ @trace()
124
+ async def async_function():
125
+ await some_async_task()
126
+ log.log_info("Async operation completed")
127
+ ```
128
+
129
+ ### 5. Performance Metrics
130
+
131
+ Automatic performance tracking is enabled with `show_metrics=True`:
132
+
133
+ ```python
134
+ Setup.initialize("MyApp", show_metrics=True)
135
+
136
+ @trace()
137
+ def monitored_function():
138
+ # Function execution time will be automatically logged
139
+ pass
140
+
141
+ # At program exit, prints performance summary:
142
+ # === Tracing Performance Metrics Summary ===
143
+ # Function Calls Total(s) Avg(s)
144
+ # --------------------------------------------------------------------
145
+ # my_module.monitored_function 10 1.23456 0.12346
146
+ ```
147
+
148
+ ### 6. Log Rotation
149
+
150
+ Configure automatic log rotation based on file size:
151
+
152
+ ```python
153
+ from pyeztrace.config import config
154
+
155
+ config.max_size = 10 * 1024 * 1024 # 10MB
156
+ config.backup_count = 5 # Keep 5 backup files
157
+ config.log_dir = "logs" # Custom log directory
158
+ config.log_file = "app.log" # Custom log filename
159
+ ```
160
+
161
+ ### 7. Error Handling and Debug Support
162
+
163
+ ```python
164
+ # Different log levels
165
+ log.log_debug("Debug information")
166
+ log.log_info("Normal operation")
167
+ log.log_warning("Warning message")
168
+ log.log_error("Error occurred")
169
+
170
+ try:
171
+ # Your code
172
+ except Exception as e:
173
+ # Automatically log exception with stack trace
174
+ log.raise_exception_to_log(e, "Custom error message", stack=True)
175
+ ```
176
+
177
+ ### 8. Thread-Safe High-Volume Logging
178
+
179
+ The logging system is designed for high-volume scenarios with thread-safe implementation:
180
+
181
+ ```python
182
+ from concurrent.futures import ThreadPoolExecutor
183
+
184
+ @trace()
185
+ def concurrent_operation(worker_id):
186
+ with log.with_context(worker_id=worker_id):
187
+ log.log_info("Worker started")
188
+ # ... work ...
189
+ log.log_info("Worker finished")
190
+
191
+ with ThreadPoolExecutor(max_workers=5) as executor:
192
+ executor.map(concurrent_operation, range(5))
193
+ ```
194
+
195
+ ## Configuration
196
+
197
+ All configuration options can be set via environment variables or code:
198
+
199
+ ```python
200
+ # Via environment variables
201
+ export EZTRACE_LOG_FORMAT="json"
202
+ export EZTRACE_LOG_LEVEL="DEBUG"
203
+ export EZTRACE_LOG_FILE="custom.log"
204
+ export EZTRACE_MAX_SIZE="10485760" # 10MB
205
+ export EZTRACE_BACKUP_COUNT="5"
206
+
207
+ # Via code
208
+ from pyeztrace.config import config
209
+ config.format = "json"
210
+ config.log_level = "DEBUG"
211
+ config.log_file = "custom.log"
212
+ config.max_size = 10 * 1024 * 1024 # 10MB
213
+ config.backup_count = 5
214
+ ```
215
+
216
+ ## Contributing
217
+
218
+ Contributions are welcome! Please read our [Contributing Guidelines](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
219
+
220
+ ## License
221
+
222
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
File without changes
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env python3
2
+ """Command-line interface for PyEzTrace log analysis."""
3
+
4
+ import argparse
5
+ import json
6
+ from datetime import datetime
7
+ from pathlib import Path
8
+ from typing import List, Optional
9
+ import re
10
+
11
+ class LogAnalyzer:
12
+ def __init__(self, log_file: Path):
13
+ self.log_file = log_file
14
+
15
+ def parse_logs(self, filter_level: Optional[str] = None,
16
+ since: Optional[datetime] = None,
17
+ until: Optional[datetime] = None,
18
+ context: Optional[dict] = None) -> List[dict]:
19
+ """Parse and filter log entries."""
20
+ entries = []
21
+
22
+ with open(self.log_file, 'r') as f:
23
+ for line in f:
24
+ try:
25
+ entry = self._parse_line(line.strip())
26
+ if self._should_include(entry, filter_level, since, until, context):
27
+ entries.append(entry)
28
+ except:
29
+ continue # Skip invalid lines
30
+
31
+ return entries
32
+
33
+ def analyze_performance(self, function_name: Optional[str] = None) -> dict:
34
+ """Analyze performance metrics from logs."""
35
+ metrics = {}
36
+ entries = self.parse_logs()
37
+
38
+ for entry in entries:
39
+ if 'duration' not in entry:
40
+ continue
41
+
42
+ func = entry.get('function', 'unknown')
43
+ if function_name and func != function_name:
44
+ continue
45
+
46
+ if func not in metrics:
47
+ metrics[func] = {
48
+ 'count': 0,
49
+ 'total_time': 0,
50
+ 'min_time': float('inf'),
51
+ 'max_time': 0,
52
+ }
53
+
54
+ m = metrics[func]
55
+ duration = float(entry['duration'])
56
+ m['count'] += 1
57
+ m['total_time'] += duration
58
+ m['min_time'] = min(m['min_time'], duration)
59
+ m['max_time'] = max(m['max_time'], duration)
60
+
61
+ # Calculate averages
62
+ for m in metrics.values():
63
+ m['avg_time'] = m['total_time'] / m['count']
64
+
65
+ return metrics
66
+
67
+ def find_errors(self, since: Optional[datetime] = None) -> List[dict]:
68
+ """Find error entries in logs."""
69
+ return self.parse_logs(filter_level="ERROR", since=since)
70
+
71
+ def _parse_line(self, line: str) -> dict:
72
+ """Parse a single log line."""
73
+ try:
74
+ # Try JSON format first
75
+ return json.loads(line)
76
+ except:
77
+ # Fall back to parsing other formats
78
+ return self._parse_plain_format(line)
79
+
80
+ def _parse_plain_format(self, line: str) -> dict:
81
+ """Parse plain text format."""
82
+ pattern = r'(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}) - (\w+) - \[([^\]]+)\](.*)'
83
+ match = re.match(pattern, line)
84
+ if not match:
85
+ raise ValueError("Invalid log format")
86
+
87
+ timestamp, level, project, rest = match.groups()
88
+ return {
89
+ 'timestamp': timestamp,
90
+ 'level': level,
91
+ 'project': project,
92
+ 'message': rest.strip()
93
+ }
94
+
95
+ def _should_include(self, entry: dict,
96
+ filter_level: Optional[str] = None,
97
+ since: Optional[datetime] = None,
98
+ until: Optional[datetime] = None,
99
+ context: Optional[dict] = None) -> bool:
100
+ """Check if log entry matches filters."""
101
+ if filter_level and entry.get('level') != filter_level:
102
+ return False
103
+
104
+ timestamp = datetime.fromisoformat(entry['timestamp'])
105
+ if since and timestamp < since:
106
+ return False
107
+ if until and timestamp > until:
108
+ return False
109
+
110
+ if context:
111
+ entry_context = entry.get('data', {})
112
+ return all(entry_context.get(k) == v for k, v in context.items())
113
+
114
+ return True
115
+
116
+ def main():
117
+ parser = argparse.ArgumentParser(description="PyEzTrace Log Analyzer")
118
+ parser.add_argument('log_file', type=Path, help="Path to log file")
119
+ parser.add_argument('--level', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'],
120
+ help="Filter by log level")
121
+ parser.add_argument('--since', type=str, help="Show logs since (YYYY-MM-DD[THH:MM:SS])")
122
+ parser.add_argument('--until', type=str, help="Show logs until (YYYY-MM-DD[THH:MM:SS])")
123
+ parser.add_argument('--context', type=str, help="Filter by context (key=value[,key=value])")
124
+ parser.add_argument('--analyze', action='store_true', help="Show performance metrics")
125
+ parser.add_argument('--function', type=str, help="Analyze specific function")
126
+ parser.add_argument('--errors', action='store_true', help="Show only errors")
127
+ parser.add_argument('--format', choices=['text', 'json'], default='text',
128
+ help="Output format")
129
+
130
+ args = parser.parse_args()
131
+
132
+ # Parse datetime arguments
133
+ since = datetime.fromisoformat(args.since) if args.since else None
134
+ until = datetime.fromisoformat(args.until) if args.until else None
135
+
136
+ # Parse context filters
137
+ context = {}
138
+ if args.context:
139
+ for pair in args.context.split(','):
140
+ key, value = pair.split('=')
141
+ context[key.strip()] = value.strip()
142
+
143
+ analyzer = LogAnalyzer(args.log_file)
144
+
145
+ if args.analyze:
146
+ metrics = analyzer.analyze_performance(args.function)
147
+ if args.format == 'json':
148
+ print(json.dumps(metrics, indent=2))
149
+ else:
150
+ for func, m in metrics.items():
151
+ print(f"\nFunction: {func}")
152
+ print(f" Calls: {m['count']}")
153
+ print(f" Total: {m['total_time']:.3f}s")
154
+ print(f" Average: {m['avg_time']:.3f}s")
155
+ print(f" Min: {m['min_time']:.3f}s")
156
+ print(f" Max: {m['max_time']:.3f}s")
157
+
158
+ elif args.errors:
159
+ errors = analyzer.find_errors(since)
160
+ if args.format == 'json':
161
+ print(json.dumps(errors, indent=2))
162
+ else:
163
+ for error in errors:
164
+ print(f"\n{error['timestamp']} - {error['message']}")
165
+ if 'data' in error:
166
+ print(f"Context: {json.dumps(error['data'], indent=2)}")
167
+
168
+ else:
169
+ entries = analyzer.parse_logs(args.level, since, until, context)
170
+ if args.format == 'json':
171
+ print(json.dumps(entries, indent=2))
172
+ else:
173
+ for entry in entries:
174
+ print(f"{entry['timestamp']} - {entry['level']} - {entry['message']}")
175
+
176
+ if __name__ == '__main__':
177
+ main()
@@ -0,0 +1,24 @@
1
+ from pydantic_settings import BaseSettings
2
+ from pydantic import ConfigDict
3
+ from typing import Optional
4
+ import os
5
+ from pathlib import Path
6
+
7
+ class LogConfig(BaseSettings):
8
+ """Configuration for the logging system."""
9
+ format: str = os.environ.get("EZTRACE_LOG_FORMAT", "color")
10
+ log_file: str = "app.log"
11
+ max_size: int = 10 * 1024 * 1024 # 10MB
12
+ backup_count: int = 5
13
+ log_dir: str = "logs"
14
+ log_level: str = "DEBUG"
15
+
16
+ model_config = ConfigDict(env_prefix="EZTRACE_")
17
+
18
+ def get_log_path(self) -> Path:
19
+ """Get the full path to the log file."""
20
+ if os.path.isabs(self.log_file):
21
+ return Path(self.log_file)
22
+ return Path(self.log_dir) / self.log_file
23
+
24
+ config = LogConfig()