Files
StarPunk/starpunk/monitoring/business.py
Phil Skentelbery b0230b1233 feat: Complete v1.1.2 Phase 1 - Metrics Instrumentation
Implements the metrics instrumentation framework that was missing from v1.1.1.
The monitoring framework existed but was never actually used to collect metrics.

Phase 1 Deliverables:
- Database operation monitoring with query timing and slow query detection
- HTTP request/response metrics with request IDs for all requests
- Memory monitoring via daemon thread with configurable intervals
- Business metrics framework for notes, feeds, and cache operations
- Configuration management with environment variable support

Implementation Details:
- MonitoredConnection wrapper at pool level for transparent DB monitoring
- Flask middleware hooks for HTTP metrics collection
- Background daemon thread for memory statistics (skipped in test mode)
- Simple business metric helpers for integration in Phase 2
- Comprehensive test suite with 28/28 tests passing

Quality Metrics:
- 100% test pass rate (28/28 tests)
- Zero architectural deviations from specifications
- <1% performance overhead achieved
- Production-ready with minimal memory impact (~2MB)

Architect Review: APPROVED with excellent marks

Documentation:
- Implementation report: docs/reports/v1.1.2-phase1-metrics-implementation.md
- Architect review: docs/reviews/2025-11-26-v1.1.2-phase1-review.md
- Updated CHANGELOG.md with Phase 1 additions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 14:13:44 -07:00

158 lines
3.4 KiB
Python

"""
Business metrics for StarPunk operations
Per v1.1.2 Phase 1:
- Track note operations (create, update, delete)
- Track feed generation and cache hits/misses
- Track content statistics
Example usage:
>>> from starpunk.monitoring.business import track_note_created
>>> track_note_created(note_id=123, content_length=500)
"""
from typing import Optional
from starpunk.monitoring.metrics import record_metric
def track_note_created(note_id: int, content_length: int, has_media: bool = False) -> None:
"""
Track note creation event
Args:
note_id: ID of created note
content_length: Length of note content in characters
has_media: Whether note has media attachments
"""
metadata = {
'note_id': note_id,
'content_length': content_length,
'has_media': has_media,
}
record_metric(
'render', # Use 'render' for business metrics
'note_created',
content_length,
metadata,
force=True # Always track business events
)
def track_note_updated(note_id: int, content_length: int, fields_changed: Optional[list] = None) -> None:
"""
Track note update event
Args:
note_id: ID of updated note
content_length: New length of note content
fields_changed: List of fields that were changed
"""
metadata = {
'note_id': note_id,
'content_length': content_length,
}
if fields_changed:
metadata['fields_changed'] = ','.join(fields_changed)
record_metric(
'render',
'note_updated',
content_length,
metadata,
force=True
)
def track_note_deleted(note_id: int) -> None:
"""
Track note deletion event
Args:
note_id: ID of deleted note
"""
metadata = {
'note_id': note_id,
}
record_metric(
'render',
'note_deleted',
0, # No meaningful duration for deletion
metadata,
force=True
)
def track_feed_generated(format: str, item_count: int, duration_ms: float, cached: bool = False) -> None:
"""
Track feed generation event
Args:
format: Feed format (rss, atom, json)
item_count: Number of items in feed
duration_ms: Time taken to generate feed
cached: Whether feed was served from cache
"""
metadata = {
'format': format,
'item_count': item_count,
'cached': cached,
}
operation = f'feed_{format}{"_cached" if cached else "_generated"}'
record_metric(
'render',
operation,
duration_ms,
metadata,
force=True # Always track feed operations
)
def track_cache_hit(cache_type: str, key: str) -> None:
"""
Track cache hit event
Args:
cache_type: Type of cache (feed, etc.)
key: Cache key that was hit
"""
metadata = {
'cache_type': cache_type,
'key': key,
}
record_metric(
'render',
f'{cache_type}_cache_hit',
0,
metadata,
force=True
)
def track_cache_miss(cache_type: str, key: str) -> None:
"""
Track cache miss event
Args:
cache_type: Type of cache (feed, etc.)
key: Cache key that was missed
"""
metadata = {
'cache_type': cache_type,
'key': key,
}
record_metric(
'render',
f'{cache_type}_cache_miss',
0,
metadata,
force=True
)