Skip to content

Commit a41add3

Browse files
committed
support set span finish time
1 parent d53626f commit a41add3

File tree

6 files changed

+81
-31
lines changed

6 files changed

+81
-31
lines changed

CHANGLOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
### Added
33
- add to_runnable decorator
44
- lcc tool message add name and tool_call_id
5+
- support set finish time of span
56

67
## [0.1.24] - 2026-01-16
78
### Added

cozeloop/decorator/decorator.py

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,6 @@ async def async_stream_wrapper(*args: Any, **kwargs: Any):
313313
else:
314314
return decorator(func)
315315

316-
317316
def to_runnable(
318317
self,
319318
func: Callable = None,
@@ -341,11 +340,16 @@ def sync_wrapper(*args: Any, **kwargs: Any):
341340
config = _convert_config(config)
342341
res = None
343342
try:
344-
inp = {
345-
"args": args,
346-
"kwargs": kwargs
347-
}
348-
res = RunnableLambda(_param_wrapped_func).invoke(input=inp, config=config)
343+
extra = {}
344+
if len(args) > 0 and is_class_func(func):
345+
extra = {"_inner_class_self": args[0]}
346+
args = args[1:]
347+
inp = {}
348+
if len(args) > 0:
349+
inp['args'] = args
350+
if len(kwargs) > 0:
351+
inp['kwargs'] = kwargs
352+
res = RunnableLambda(_param_wrapped_func).invoke(input=inp, config=config, **extra)
349353
if hasattr(res, "__iter__"):
350354
return res
351355
except StopIteration:
@@ -362,11 +366,16 @@ async def async_wrapper(*args: Any, **kwargs: Any):
362366
config = _convert_config(config)
363367
res = None
364368
try:
365-
inp = {
366-
"args": args,
367-
"kwargs": kwargs
368-
}
369-
res = await RunnableLambda(_param_wrapped_func_async).ainvoke(input=inp, config=config)
369+
extra = {}
370+
if len(args) > 0 and is_class_func(func):
371+
extra = {"_inner_class_self": args[0]}
372+
args = args[1:]
373+
inp = {}
374+
if len(args) > 0:
375+
inp['args'] = args
376+
if len(kwargs) > 0:
377+
inp['kwargs'] = kwargs
378+
res = await RunnableLambda(_param_wrapped_func_async).ainvoke(input=inp, config=config, **extra)
370379
if hasattr(res, "__aiter__"):
371380
return res
372381
except StopIteration:
@@ -387,11 +396,16 @@ def gen_wrapper(*args: Any, **kwargs: Any):
387396
config = kwargs.pop("config", None)
388397
config = _convert_config(config)
389398
try:
390-
inp = {
391-
"args": args,
392-
"kwargs": kwargs
393-
}
394-
gen = RunnableLambda(_param_wrapped_func).invoke(input=inp, config=config)
399+
extra = {}
400+
if len(args) > 0 and is_class_func(func):
401+
extra = {"_inner_class_self": args[0]}
402+
args = args[1:]
403+
inp = {}
404+
if len(args) > 0:
405+
inp['args'] = args
406+
if len(kwargs) > 0:
407+
inp['kwargs'] = kwargs
408+
gen = RunnableLambda(_param_wrapped_func).invoke(input=inp, config=config, *extra)
395409
try:
396410
for item in gen:
397411
yield item
@@ -405,11 +419,16 @@ async def async_gen_wrapper(*args: Any, **kwargs: Any):
405419
config = kwargs.pop("config", None)
406420
config = _convert_config(config)
407421
try:
408-
inp = {
409-
"args": args,
410-
"kwargs": kwargs
411-
}
412-
gen = RunnableLambda(_param_wrapped_func_async).invoke(input=inp, config=config)
422+
extra = {}
423+
if len(args) > 0 and is_class_func(func):
424+
extra = {"_inner_class_self": args[0]}
425+
args = args[1:]
426+
inp = {}
427+
if len(args) > 0:
428+
inp['args'] = args
429+
if len(kwargs) > 0:
430+
inp['kwargs'] = kwargs
431+
gen = RunnableLambda(_param_wrapped_func_async).invoke(input=inp, config=config, **extra)
413432
items = []
414433
try:
415434
async for item in gen:
@@ -428,15 +447,25 @@ async def async_gen_wrapper(*args: Any, **kwargs: Any):
428447
raise e
429448

430449
# for convert parameter
431-
def _param_wrapped_func(input_dict: dict) -> Any:
432-
args = input_dict.get("args", ())
433-
kwargs = input_dict.get("kwargs", {})
434-
return func(*args, **kwargs)
435-
436-
async def _param_wrapped_func_async(input_dict: dict) -> Any:
437-
args = input_dict.get("args", ())
438-
kwargs = input_dict.get("kwargs", {})
439-
return await func(*args, **kwargs)
450+
def _param_wrapped_func(input_dict: dict, **kwargs) -> Any:
451+
real_args = input_dict.get("args", ())
452+
real_kwargs = input_dict.get("kwargs", {})
453+
454+
inner_class_self = kwargs.get("_inner_class_self", None)
455+
if inner_class_self is not None:
456+
real_args = (inner_class_self, *real_args)
457+
458+
return func(*real_args, **real_kwargs)
459+
460+
async def _param_wrapped_func_async(input_dict: dict, **kwargs) -> Any:
461+
real_args = input_dict.get("args", ())
462+
real_kwargs = input_dict.get("kwargs", {})
463+
464+
inner_class_self = kwargs.get("_inner_class_self", None)
465+
if inner_class_self is not None:
466+
real_args = (inner_class_self, *real_args)
467+
468+
return await func(*real_args, **real_kwargs)
440469

441470
def _convert_config(config: RunnableConfig = None) -> RunnableConfig | None:
442471
if config is None:

cozeloop/internal/trace/noop_span.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ def set_system_tags(self, system_tags: Dict[str, Any]) -> None:
125125
def set_deployment_env(self, deployment_env: str) -> None:
126126
pass
127127

128+
def set_finish_time(self, finish_time: datetime) -> None:
129+
pass
130+
128131
def __enter__(self):
129132
return self
130133

cozeloop/internal/trace/span.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ def __init__(self, span_type: str = '', name: str = '', space_id: str = '', trac
7878
self.space_id = space_id
7979
self.parent_span_id = parent_span_id
8080
self.start_time = start_time if start_time else datetime.now()
81+
self.finish_time: datetime = None
8182
self.duration = duration
8283
self.tag_map = tag_map if tag_map else {}
8384
self.system_tag_map = system_tag_map if system_tag_map else {}
@@ -396,6 +397,10 @@ def set_system_tags(self, system_tags: Dict[str, Any]) -> None:
396397
def set_deployment_env(self, deployment_env: str) -> None:
397398
self.set_tags({DEPLOYMENT_ENV: deployment_env})
398399

400+
def set_finish_time(self, finish_time: datetime) -> None:
401+
self.finish_time = finish_time
402+
403+
399404
def get_rectified_map(self, input_map: Dict[str, Any]) -> (Dict[str, Any], List[str], int):
400405
validate_map = {}
401406
cut_off_keys = []
@@ -541,7 +546,10 @@ def set_stat_info(self):
541546
if input_tokens > 0 or output_tokens > 0:
542547
self.set_tags({TOKENS: int(input_tokens) + int(output_tokens)})
543548

544-
duration = int((datetime.now().timestamp() - self.start_time.timestamp()) * 1000000)
549+
finish_time_stamp = datetime.now().timestamp()
550+
if self.finish_time is not None:
551+
finish_time_stamp = self.finish_time.timestamp()
552+
duration = int((finish_time_stamp - self.start_time.timestamp()) * 1000000)
545553
with self.lock:
546554
self.duration = duration
547555

cozeloop/span.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,11 +186,18 @@ def set_system_tags(self, system_tags: Dict[str, Any]) -> None:
186186
Set system tags. DO NOT use this method unless you know what you are doing.
187187
"""
188188

189+
@abstractmethod
189190
def set_deployment_env(self, deployment_env: str) -> None:
190191
"""
191192
Set the deployment environment of the span, identify custom environments.
192193
"""
193194

195+
@abstractmethod
196+
def set_finish_time(self, finish_time: datetime) -> None:
197+
"""
198+
Set the finish time of the span.
199+
"""
200+
194201

195202
class Span(CommonSpanSetter, SpanContext):
196203
"""

examples/trace/simple.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import logging
55
import os
66
import time
7+
from datetime import datetime, timedelta
78

89
import cozeloop
910

@@ -100,6 +101,7 @@ def do_simple_demo():
100101
span.set_error(str(e))
101102

102103
# 3. span finish
104+
span.set_finish_time(datetime.now() + timedelta(seconds=3)) # set finish time as your need to change duration
103105
span.finish()
104106

105107
# 4. (optional) flush or close

0 commit comments

Comments
 (0)