11# Timestamp Capture - LLM Usage Brief
22
3- ** Version** : v3.58.0
3+ ** Version** : v3.59.1
44** Purpose** : Guide for LLMs and developers on using the timestamp_capture instrumentation system
55** Location** : ` osbot_utils.helpers.timestamp_capture `
66** Repo** : https://github.com/owasp-sbot/OSBot-Utils
@@ -103,6 +103,9 @@ from osbot_utils.helpers.timestamp_capture.Timestamp_Collector import T
103103# Decorator
104104from osbot_utils.helpers.timestamp_capture.decorators.timestamp import timestamp
105105
106+ # Decorator for dynamic names from function arguments
107+ from osbot_utils.helpers.timestamp_capture.decorators.timestamp_args import timestamp_args
108+
106109# Context manager for code blocks
107110from osbot_utils.helpers.timestamp_capture.context_managers.timestamp_block import timestamp_block
108111
@@ -299,7 +302,106 @@ def handle_delete(self):
299302| ` component.stage.action ` | ` pipeline.stage1.extract ` | Pipeline stages |
300303| ` feature.version.method ` | ` algorithm.v2.sort ` | A/B testing |
301304
302- ### Pattern 5: Programmatic Analysis
305+
306+ ### Pattern 5: Dynamic Names from Function Arguments
307+
308+ When a method is called multiple times with different arguments and you need to distinguish each call in reports, use ` @timestamp_args ` . This interpolates function argument values into the metric name at runtime.
309+ ``` python
310+ from osbot_utils.helpers.timestamp_capture.decorators.timestamp_args import timestamp_args
311+
312+ class DocumentBuilder :
313+
314+ @timestamp_args (name = " link_component({name} )" )
315+ def _link_component (self , name : str , root_id : int ):
316+ # Link a component graph to the document
317+ ...
318+
319+ # Each call is tracked separately:
320+ builder._link_component(" head" , 1 )
321+ builder._link_component(" body" , 2 )
322+ builder._link_component(" attrs" , 3 )
323+ ```
324+
325+ ** Timeline shows each call distinctly:**
326+ ```
327+ 20.879ms ▶ link_component(head)
328+ 21.846ms ◀ link_component(head)
329+ 21.860ms ▶ link_component(body)
330+ 22.659ms ◀ link_component(body)
331+ 22.671ms ▶ link_component(attrs)
332+ 23.433ms ◀ link_component(attrs)
333+ ```
334+
335+ ** Hotspots show individual breakdowns:**
336+ ```
337+ link_component(head) 0.97ms [1 call]
338+ link_component(body) 0.80ms [1 call]
339+ link_component(attrs) 0.76ms [1 call]
340+ ```
341+
342+ #### When to use ` @timestamp_args ` vs ` @timestamp `
343+
344+ | Decorator | Name Resolution | Use When |
345+ | -----------| -----------------| ----------|
346+ | ` @timestamp ` | At decoration time (static) | Same name for all calls |
347+ | ` @timestamp_args ` | At call time (dynamic) | Need to distinguish calls by argument values |
348+
349+ #### Supported Argument Patterns
350+ ``` python
351+ # Positional arguments
352+ @timestamp_args (name = " process.{item_type} " )
353+ def process (item_type : str , data : dict ):
354+ ...
355+
356+ # Multiple arguments
357+ @timestamp_args (name = " handler.{method} .{path} " )
358+ def handle_request (method : str , path : str ):
359+ ...
360+
361+ # Keyword-only arguments (after *)
362+ @timestamp_args (name = " config.{env} .{region} " )
363+ def configure (* , env : str , region : str = " us-east-1" ):
364+ ...
365+
366+ # Mixed positional and keyword-only
367+ @timestamp_args (name = " request.{method} " )
368+ def make_request (method : str , * , timeout : int = 30 ):
369+ ...
370+
371+ # Using default values (defaults are interpolated too)
372+ @timestamp_args (name = " cache.{strategy} " )
373+ def cache_data (data : dict , * , strategy : str = " lru" ):
374+ ...
375+ # cache_data({"a": 1}) → "cache.lru"
376+ # cache_data({"a": 1}, strategy="fifo") → "cache.fifo"
377+ ```
378+
379+ #### Real-World Example
380+ ``` python
381+ class Html_MGraph__Document :
382+
383+ @timestamp (name = " html_mgraph.document.setup" )
384+ def setup (self ):
385+ self .head_graph = Html_MGraph__Head().setup()
386+ self .body_graph = Html_MGraph__Body().setup()
387+ self .attrs_graph = Html_MGraph__Attributes().setup()
388+
389+ # Each link is tracked separately
390+ self ._link_component_graph(' head' , self .head_graph.root_id)
391+ self ._link_component_graph(' body' , self .body_graph.root_id)
392+ self ._link_component_graph(' attrs' , self .attrs_graph.root_id)
393+ return self
394+
395+ @timestamp_args (name = " html_mgraph.document._link_component_graph({name} )" )
396+ def _link_component_graph (self , name : str , component_root_id : Node_Id):
397+ # Now each call shows which component in timeline/reports
398+ ...
399+ ```
400+
401+ ** Important:** ` @timestamp_args ` requires at least one ` {placeholder} ` in the name. For static names, use ` @timestamp ` instead (lower overhead).
402+
403+
404+ ### Pattern 6: Programmatic Analysis
303405
304406``` python
305407from osbot_utils.helpers.timestamp_capture.Timestamp_Collector__Analysis import Timestamp_Collector__Analysis
@@ -329,7 +431,7 @@ by_total = analysis.get_timings_by_total()
329431by_calls = analysis.get_timings_by_call_count()
330432```
331433
332- ### Pattern 6 : Test Performance Assertions
434+ ### Pattern 7 : Test Performance Assertions
333435
334436``` python
335437def test_process_performance (self ):
@@ -549,6 +651,7 @@ with _timestamp_collector_:
549651| @timestamp , no collector | ~ 3 μs | ✅ Yes |
550652| @timestamp , with collector | ~ 8 μs | ✅ Yes (for methods >100μs) |
551653| Nested decorators (N levels) | N × overhead | ✅ Scales linearly |
654+ | @timestamp_args, with collector | ~ 10 μs | ✅ Yes (slight overhead for arg binding) |
552655
553656** Rule of thumb** : If your method takes >100μs, the 8μs capture overhead is <8% - acceptable for most scenarios including production profiling.
554657
@@ -712,6 +815,24 @@ with timestamp_block("process_all_items"):
712815MAX_STACK_DEPTH = 100 # Increase if needed
713816```
714817
818+ ### Problem: Can't Distinguish Multiple Calls to Same Method
819+
820+ ** Cause** : Using ` @timestamp ` on a method called with different arguments
821+ ``` python
822+ # ❌ All 5 calls show as same name
823+ @timestamp (name = " link_component" )
824+ def _link_component (self , name : str , root_id : int ):
825+ ...
826+ ```
827+
828+ ** Solution** : Use ` @timestamp_args ` to include argument values in the name
829+ ``` python
830+ # ✅ Each call shows distinct name
831+ @timestamp_args (name = " link_component({name} )" )
832+ def _link_component (self , name : str , root_id : int ):
833+ ...
834+ ```
835+
715836---
716837
717838## Summary Checklist
@@ -721,6 +842,7 @@ When adding timestamp capture to a codebase:
721842- [ ] Import ` @timestamp ` decorator and ` Timestamp_Collector `
722843- [ ] Add ` @timestamp ` to key methods (entry points, major processing steps)
723844- [ ] Use ` @timestamp(name="...") ` for hierarchical/grouped naming when helpful
845+ - [ ] Use ` @timestamp_args(name="method({arg})") ` when you need to distinguish calls by argument values
724846- [ ] Skip tiny utility functions and hot-loop internals
725847- [ ] Use ` timestamp_block ` for code phases not in methods
726848- [ ] Name collector variable exactly ` _timestamp_collector_ `
0 commit comments