Skip to content

Commit 61e2d03

Browse files
committed
Add standalone integration
1 parent 1da91ca commit 61e2d03

3 files changed

Lines changed: 174 additions & 92 deletions

File tree

README.md

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -71,34 +71,47 @@ pip install aiocop
7171

7272
## Quick Start
7373

74+
Copy this into a file and run it - no dependencies needed besides aiocop:
75+
7476
```python
77+
# test_aiocop.py
78+
import asyncio
7579
import aiocop
7680

77-
# Define a callback to handle slow task events
78-
def on_slow_task(event: aiocop.SlowTaskEvent) -> None:
79-
if event.exceeded_threshold:
80-
print(f"SLOW TASK DETECTED!")
81-
print(f" Elapsed: {event.elapsed_ms:.2f}ms (threshold: {event.threshold_ms}ms)")
82-
print(f" Severity: {event.severity_level} (score: {event.severity_score})")
83-
print(f" Reason: {event.reason}")
84-
for evt in event.blocking_events:
85-
print(f" - {evt['event']}")
86-
print(f" at {evt['trace']}")
87-
88-
# 1. Patch stdlib functions to emit audit events
89-
aiocop.patch_audit_functions()
90-
91-
# 2. Register the audit hook to capture blocking IO
92-
aiocop.start_blocking_io_detection(trace_depth=20)
93-
94-
# 3. Patch the event loop to detect slow tasks
95-
aiocop.detect_slow_tasks(
96-
threshold_ms=30,
97-
on_slow_task=on_slow_task,
98-
)
99-
100-
# 4. Activate monitoring when your app is ready
101-
aiocop.activate()
81+
82+
def on_slow_task(event):
83+
print(f"SLOW TASK DETECTED: {event.elapsed_ms:.1f}ms")
84+
print(f" Severity: {event.severity_level}")
85+
for evt in event.blocking_events:
86+
print(f" - {evt['event']} at {evt['entry_point']}")
87+
88+
89+
async def blocking_task():
90+
# This synchronous open() will block the loop - aiocop will catch it!
91+
with open("/dev/null", "w") as f:
92+
f.write("data")
93+
await asyncio.sleep(0.1)
94+
95+
96+
async def main():
97+
aiocop.patch_audit_functions()
98+
aiocop.start_blocking_io_detection()
99+
aiocop.detect_slow_tasks(threshold_ms=10, on_slow_task=on_slow_task)
100+
aiocop.activate()
101+
102+
await asyncio.gather(blocking_task(), blocking_task())
103+
104+
105+
if __name__ == "__main__":
106+
asyncio.run(main())
107+
```
108+
109+
```bash
110+
python test_aiocop.py
111+
# Output:
112+
# SLOW TASK DETECTED: 102.3ms
113+
# Severity: medium
114+
# - open(/dev/null, w) at test_aiocop.py:14:blocking_task
102115
```
103116

104117
## Usage with ASGI (FastAPI, Starlette, etc.)

docs/integrations.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Real-world examples of integrating aiocop with popular frameworks and tools.
44

55
## Table of Contents
66

7+
- [Standalone (No Framework)](#standalone-no-framework)
78
- [FastAPI](#fastapi)
89
- [Starlette](#starlette)
910
- [aiohttp](#aiohttp)
@@ -12,6 +13,71 @@ Real-world examples of integrating aiocop with popular frameworks and tools.
1213
- [Structured Logging](#structured-logging)
1314
- [Sentry](#sentry)
1415

16+
## Standalone (No Framework)
17+
18+
A minimal example with no dependencies - just Python and aiocop:
19+
20+
```python
21+
# test_aiocop.py
22+
import asyncio
23+
import aiocop
24+
25+
26+
def on_slow_task(event):
27+
print(f"SLOW TASK DETECTED: {event.elapsed_ms:.1f}ms")
28+
print(f" Severity: {event.severity_level}")
29+
print(f" Blocking events: {len(event.blocking_events)}")
30+
for evt in event.blocking_events:
31+
print(f" - {evt['event']} at {evt['entry_point']}")
32+
33+
34+
async def blocking_task():
35+
print("Executing task...")
36+
# This synchronous open() will block the loop!
37+
with open("/dev/null", "w") as f:
38+
f.write("data")
39+
await asyncio.sleep(0.1)
40+
41+
42+
async def main():
43+
# Setup aiocop
44+
aiocop.patch_audit_functions()
45+
aiocop.start_blocking_io_detection(trace_depth=5)
46+
aiocop.detect_slow_tasks(threshold_ms=10, on_slow_task=on_slow_task)
47+
aiocop.activate()
48+
49+
# Run your code as normal
50+
await asyncio.gather(blocking_task(), blocking_task())
51+
52+
aiocop.deactivate()
53+
54+
55+
if __name__ == "__main__":
56+
asyncio.run(main())
57+
```
58+
59+
Run it:
60+
61+
```bash
62+
pip install aiocop
63+
python test_aiocop.py
64+
```
65+
66+
Output:
67+
68+
```
69+
Executing task...
70+
Executing task...
71+
SLOW TASK DETECTED: 102.3ms
72+
Severity: medium
73+
Blocking events: 1
74+
- open(/dev/null, w) at test_aiocop.py:15:blocking_task
75+
SLOW TASK DETECTED: 103.1ms
76+
Severity: medium
77+
Blocking events: 1
78+
- open(/dev/null, w) at test_aiocop.py:15:blocking_task
79+
```
80+
1581
## FastAPI
1682

1783
### Basic Integration

docs/quickstart.md

Lines changed: 70 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,69 @@ Get aiocop running in 5 minutes.
88
pip install aiocop
99
```
1010

11-
## Basic Setup
11+
## Try It Now
12+
13+
Copy this into a file and run it - no dependencies needed:
14+
15+
```python
16+
# test_aiocop.py
17+
import asyncio
18+
import aiocop
19+
20+
21+
def on_slow_task(event):
22+
print(f"SLOW TASK DETECTED: {event.elapsed_ms:.1f}ms")
23+
print(f" Severity: {event.severity_level}")
24+
print(f" Blocking events: {len(event.blocking_events)}")
25+
for evt in event.blocking_events:
26+
print(f" - {evt['event']} at {evt['entry_point']}")
27+
28+
29+
async def blocking_task():
30+
print("Executing task...")
31+
# This synchronous open() will block the loop!
32+
with open("/dev/null", "w") as f:
33+
f.write("data")
34+
await asyncio.sleep(0.1)
35+
36+
37+
async def main():
38+
# Setup aiocop
39+
aiocop.patch_audit_functions()
40+
aiocop.start_blocking_io_detection(trace_depth=5)
41+
aiocop.detect_slow_tasks(threshold_ms=10, on_slow_task=on_slow_task)
42+
aiocop.activate()
43+
44+
# Run your code as normal
45+
await asyncio.gather(blocking_task(), blocking_task())
46+
47+
aiocop.deactivate()
48+
49+
50+
if __name__ == "__main__":
51+
asyncio.run(main())
52+
```
53+
54+
```bash
55+
python test_aiocop.py
56+
```
57+
58+
**Output:**
59+
60+
```
61+
Executing task...
62+
Executing task...
63+
SLOW TASK DETECTED: 102.3ms
64+
Severity: medium
65+
Blocking events: 1
66+
- open(/dev/null, w) at test_aiocop.py:15:blocking_task
67+
SLOW TASK DETECTED: 103.1ms
68+
Severity: medium
69+
Blocking events: 1
70+
- open(/dev/null, w) at test_aiocop.py:15:blocking_task
71+
```
72+
73+
## Understanding the Setup
1274

1375
aiocop requires three setup steps, then activation:
1476

@@ -30,84 +92,25 @@ aiocop.activate()
3092

3193
That's it! aiocop is now monitoring your async code.
3294

33-
## Adding a Callback
95+
## The Callback
3496

35-
To actually see the detected events, register a callback:
97+
The callback receives a `SlowTaskEvent` with all the details:
3698

3799
```python
38-
import aiocop
39-
40100
def on_slow_task(event: aiocop.SlowTaskEvent) -> None:
41101
# Callback is invoked for ALL blocking I/O, not just slow tasks.
42102
# Use exceeded_threshold to check if it was actually slow.
43103
if event.exceeded_threshold:
44104
print(f"SLOW TASK: {event.elapsed_ms:.1f}ms (threshold: {event.threshold_ms}ms)")
45-
print(f" Severity: {event.severity_level} (score: {event.severity_score})")
46-
print(f" Reason: {event.reason}")
47-
48-
for evt in event.blocking_events:
49-
print(f" - {evt['event']}")
50-
print(f" at {evt['trace']}")
51-
52-
# Setup
53-
aiocop.patch_audit_functions()
54-
aiocop.start_blocking_io_detection()
55-
aiocop.detect_slow_tasks(threshold_ms=30, on_slow_task=on_slow_task)
56-
aiocop.activate()
57-
```
58-
59-
**Note:** The callback is invoked for **all tasks with blocking I/O detected**, even fast ones. Check `event.exceeded_threshold` to filter for slow tasks only.
105+
print(f" Severity: {event.severity_level} (score: {event.severity_score})")
106+
print(f" Reason: {event.reason}")
60107

61-
## Complete Example
62-
63-
Here's a complete example that demonstrates aiocop detecting blocking I/O:
64-
65-
```python
66-
import asyncio
67-
import time
68-
import aiocop
69-
70-
def on_slow_task(event: aiocop.SlowTaskEvent) -> None:
71-
if event.exceeded_threshold:
72-
print(f"\nBlocking detected!")
73-
print(f" Duration: {event.elapsed_ms:.1f}ms")
74-
print(f" Severity: {event.severity_level}")
75108
for evt in event.blocking_events:
76-
print(f" - {evt['event']}")
77-
78-
async def bad_async_function():
79-
"""This function has a blocking call - aiocop will detect it!"""
80-
await asyncio.sleep(0.01) # This is fine (async)
81-
time.sleep(0.05) # This is BAD (blocking) - aiocop will catch it!
82-
await asyncio.sleep(0.01) # This is fine (async)
83-
84-
async def main():
85-
# Setup aiocop
86-
aiocop.patch_audit_functions()
87-
aiocop.start_blocking_io_detection()
88-
aiocop.detect_slow_tasks(threshold_ms=30, on_slow_task=on_slow_task)
89-
aiocop.activate()
90-
91-
print("Running async task with blocking call...")
92-
await bad_async_function()
93-
print("\nDone!")
94-
95-
if __name__ == "__main__":
96-
asyncio.run(main())
97-
```
98-
99-
**Output:**
100-
109+
print(f" - {evt['event']}")
110+
print(f" at {evt['trace']}")
101111
```
102-
Running async task with blocking call...
103-
104-
Blocking detected!
105-
Duration: 52.3ms
106-
Severity: high
107-
- time.sleep(0.05)
108112

109-
Done!
110-
```
113+
**Note:** The callback is invoked for **all tasks with blocking I/O detected**, even fast ones. Check `event.exceeded_threshold` to filter for slow tasks only.
111114

112115
## What Gets Detected?
113116

0 commit comments

Comments
 (0)