monocle-apptrace 0.6.0__tar.gz → 0.7.0__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.
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/PKG-INFO +16 -4
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/pyproject.toml +48 -11
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/exporters/aws/s3_exporter.py +99 -41
- monocle_apptrace-0.7.0/src/monocle_apptrace/exporters/azure/blob_exporter.py +208 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/exporters/base_exporter.py +10 -1
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/exporters/file_exporter.py +3 -3
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/exporters/okahu/okahu_exporter.py +1 -15
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/common/__init__.py +2 -1
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/common/constants.py +58 -9
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/common/instrumentor.py +6 -1
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/common/method_wrappers.py +4 -4
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/common/scope_wrapper.py +17 -2
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/common/span_handler.py +94 -29
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/common/utils.py +157 -8
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/common/wrapper.py +111 -42
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/common/wrapper_method.py +17 -2
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/a2a/methods.py +1 -1
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/adk/_helper.py +12 -1
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/adk/adk_handler.py +27 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/adk/entities/agent.py +40 -3
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/adk/entities/tool.py +1 -1
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/adk/methods.py +4 -2
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/agents/_helper.py +9 -8
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/agents/agents_processor.py +15 -33
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/agents/entities/inference.py +17 -5
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/agents/methods.py +0 -7
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/aiohttp/_helper.py +1 -1
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/anthropic/_helper.py +55 -2
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/anthropic/entities/inference.py +15 -4
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/azfunc/_helper.py +1 -1
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/azureaiinference/_helper.py +56 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/azureaiinference/entities/inference.py +14 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/botocore/_helper.py +69 -5
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/botocore/entities/inference.py +18 -0
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/crew_ai/_helper.py +260 -0
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/crew_ai/crew_ai_processor.py +72 -0
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/crew_ai/entities/inference.py +179 -0
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/crew_ai/methods.py +70 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/fastapi/_helper.py +5 -5
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/fastapi/methods.py +4 -4
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/fastmcp/_helper.py +261 -0
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/fastmcp/entities/prompts.py +96 -0
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/fastmcp/entities/resources.py +97 -0
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/fastmcp/entities/tools.py +97 -0
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/fastmcp/methods.py +56 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/finish_types.py +35 -18
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/flask/_helper.py +3 -3
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/gemini/_helper.py +62 -3
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/gemini/entities/inference.py +16 -1
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/haystack/_helper.py +63 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/haystack/entities/inference.py +14 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/hugging_face/_helper.py +1 -1
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/hugging_face/entities/inference.py +1 -4
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/lambdafunc/_helper.py +1 -1
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/langchain/_helper.py +54 -3
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/langchain/entities/inference.py +15 -4
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/langchain/methods.py +2 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/langgraph/_helper.py +72 -8
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/langgraph/entities/inference.py +16 -5
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/langgraph/langgraph_processor.py +122 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/langgraph/methods.py +22 -6
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/litellm/_helper.py +88 -1
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/litellm/entities/inference.py +26 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/llamaindex/_helper.py +103 -10
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/llamaindex/entities/agent.py +4 -3
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/llamaindex/entities/inference.py +15 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/llamaindex/llamaindex_processor.py +25 -11
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/llamaindex/methods.py +2 -8
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/mcp/_helper.py +1 -1
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/mistral/_helper.py +91 -21
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/mistral/entities/inference.py +15 -4
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/mistral/methods.py +0 -8
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/openai/_helper.py +104 -30
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/openai/entities/inference.py +34 -4
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/openai/methods.py +1 -1
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/openai/openai_processor.py +81 -0
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/strands/_helper.py +71 -0
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/strands/entities/agent.py +179 -0
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/strands/entities/tool.py +62 -0
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/strands/methods.py +21 -0
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/strands/strands_processor.py +22 -0
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/teamsai/__init__.py +0 -0
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/teamsai/entities/__init__.py +0 -0
- monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/teamsai/entities/inference/__init__.py +0 -0
- monocle_apptrace-0.6.0/src/monocle_apptrace/exporters/azure/blob_exporter.py +0 -146
- monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/langgraph/langgraph_processor.py +0 -50
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/.gitignore +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/LICENSE +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/README.md +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/README.md +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/__main__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/exporters/aws/s3_exporter_opendal.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/exporters/azure/blob_exporter_opendal.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/exporters/exporter_processor.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/exporters/monocle_exporters.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/common/tracing.md +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/a2a/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/a2a/_helper.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/a2a/entities/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/a2a/entities/inference.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/adk/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/agents/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/agents/entities/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/aiohttp/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/aiohttp/entities/http.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/aiohttp/methods.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/anthropic/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/anthropic/entities/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/anthropic/methods.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/azfunc/entities/http.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/azfunc/methods.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/azfunc/wrapper.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/azureaiinference/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/azureaiinference/methods.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/botocore/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/botocore/entities/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/botocore/handlers/botocore_span_handler.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/botocore/methods.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/fastapi → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/crew_ai}/__init__.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/fastapi → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/crew_ai}/entities/__init__.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/flask → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/fastapi}/__init__.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/gemini → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/fastapi/entities}/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/fastapi/entities/http.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/gemini/entities → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/fastmcp}/__init__.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/haystack → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/flask}/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/flask/entities/http.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/flask/methods.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/haystack/entities → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/gemini}/__init__.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/hugging_face → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/gemini/entities}/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/gemini/entities/retrieval.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/gemini/methods.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/hugging_face/entities → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/haystack}/__init__.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/langchain → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/haystack/entities}/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/haystack/entities/retrieval.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/haystack/methods.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/langchain/entities → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/hugging_face}/__init__.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/langgraph → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/hugging_face/entities}/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/hugging_face/methods.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/lambdafunc/entities/http.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/lambdafunc/methods.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/lambdafunc/wrapper.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/langgraph/entities → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/langchain}/__init__.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/litellm → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/langchain/entities}/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/langchain/entities/retrieval.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/litellm/entities → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/langgraph}/__init__.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/llamaindex → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/langgraph/entities}/__init__.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/llamaindex/entities → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/litellm}/__init__.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/mcp → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/litellm/entities}/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/litellm/methods.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/mcp/entities → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/llamaindex}/__init__.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/mistral → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/llamaindex/entities}/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/llamaindex/entities/retrieval.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/mistral/entities → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/mcp}/__init__.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/openai → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/mcp/entities}/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/mcp/entities/inference.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/mcp/mcp_processor.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/mcp/methods.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/openai/entities → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/mistral}/__init__.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/teamsai → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/mistral/entities}/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/mistral/entities/retrieval.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/teamsai/entities → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/openai}/__init__.py +0 -0
- {monocle_apptrace-0.6.0/src/monocle_apptrace/instrumentation/metamodel/teamsai/entities/inference → monocle_apptrace-0.7.0/src/monocle_apptrace/instrumentation/metamodel/openai/entities}/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/openai/entities/retrieval.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/requests/__init__.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/requests/_helper.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/requests/entities/http.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/requests/methods.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/teamsai/_helper.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/teamsai/entities/inference/actionplanner_output_processor.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/teamsai/entities/inference/teamsai_output_processor.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/teamsai/methods.py +0 -0
- {monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/instrumentation/metamodel/teamsai/sample.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: monocle_apptrace
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: package with monocle genAI tracing
|
|
5
5
|
Project-URL: Homepage, https://github.com/monocle2ai/monocle
|
|
6
6
|
Project-URL: Issues, https://github.com/monocle2ai/monocle/issues
|
|
@@ -14,6 +14,7 @@ Requires-Dist: opentelemetry-api>=1.21.0
|
|
|
14
14
|
Requires-Dist: opentelemetry-instrumentation
|
|
15
15
|
Requires-Dist: opentelemetry-sdk>=1.21.0
|
|
16
16
|
Requires-Dist: requests
|
|
17
|
+
Requires-Dist: rfc3986>=2.0.0
|
|
17
18
|
Requires-Dist: wrapt>=1.14.0
|
|
18
19
|
Provides-Extra: ai-test
|
|
19
20
|
Requires-Dist: bert-score; extra == 'ai-test'
|
|
@@ -21,20 +22,23 @@ Requires-Dist: transformers; extra == 'ai-test'
|
|
|
21
22
|
Provides-Extra: aws
|
|
22
23
|
Requires-Dist: boto3==1.37.24; extra == 'aws'
|
|
23
24
|
Provides-Extra: azure
|
|
25
|
+
Requires-Dist: azure-ai-inference; extra == 'azure'
|
|
24
26
|
Requires-Dist: azure-storage-blob==12.22.0; extra == 'azure'
|
|
25
27
|
Provides-Extra: dev
|
|
26
28
|
Requires-Dist: a2a-sdk==0.3.6; extra == 'dev'
|
|
27
29
|
Requires-Dist: anthropic-haystack; extra == 'dev'
|
|
28
30
|
Requires-Dist: anthropic==0.57.1; extra == 'dev'
|
|
29
31
|
Requires-Dist: azure-storage-blob==12.22.0; extra == 'dev'
|
|
30
|
-
Requires-Dist: boto3==1.
|
|
32
|
+
Requires-Dist: boto3==1.39.0; extra == 'dev'
|
|
31
33
|
Requires-Dist: chromadb==1.0.15; extra == 'dev'
|
|
32
34
|
Requires-Dist: click==8.2.1; extra == 'dev'
|
|
33
|
-
Requires-Dist:
|
|
35
|
+
Requires-Dist: crewai==0.95.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: datasets==4.3.0; extra == 'dev'
|
|
34
37
|
Requires-Dist: faiss-cpu==1.8.0; extra == 'dev'
|
|
35
38
|
Requires-Dist: fastapi>=0.115.0; extra == 'dev'
|
|
36
39
|
Requires-Dist: flask; extra == 'dev'
|
|
37
40
|
Requires-Dist: google-adk==1.10.0; extra == 'dev'
|
|
41
|
+
Requires-Dist: google-ai-haystack; extra == 'dev'
|
|
38
42
|
Requires-Dist: google-generativeai==0.8.5; extra == 'dev'
|
|
39
43
|
Requires-Dist: haystack-ai==2.3.0; extra == 'dev'
|
|
40
44
|
Requires-Dist: httpx==0.28.1; extra == 'dev'
|
|
@@ -52,6 +56,7 @@ Requires-Dist: langchain==0.3.25; extra == 'dev'
|
|
|
52
56
|
Requires-Dist: langchainhub==0.1.21; extra == 'dev'
|
|
53
57
|
Requires-Dist: langgraph-supervisor==0.0.28; extra == 'dev'
|
|
54
58
|
Requires-Dist: langgraph==0.5.4; extra == 'dev'
|
|
59
|
+
Requires-Dist: litellm==1.77.5; extra == 'dev'
|
|
55
60
|
Requires-Dist: llama-index-embeddings-huggingface==0.6.0; extra == 'dev'
|
|
56
61
|
Requires-Dist: llama-index-llms-anthropic==0.8.1; extra == 'dev'
|
|
57
62
|
Requires-Dist: llama-index-llms-azure-openai==0.4.0; extra == 'dev'
|
|
@@ -72,12 +77,19 @@ Requires-Dist: opentelemetry-instrumentation-flask; extra == 'dev'
|
|
|
72
77
|
Requires-Dist: parameterized==0.9.0; extra == 'dev'
|
|
73
78
|
Requires-Dist: pydantic==2.11.7; extra == 'dev'
|
|
74
79
|
Requires-Dist: pytest-asyncio==0.26.0; extra == 'dev'
|
|
80
|
+
Requires-Dist: pytest-venv; extra == 'dev'
|
|
75
81
|
Requires-Dist: pytest==8.3.5; extra == 'dev'
|
|
76
82
|
Requires-Dist: python-dotenv>=1.1.0; extra == 'dev'
|
|
77
83
|
Requires-Dist: requests-aws4auth==1.2.3; extra == 'dev'
|
|
78
|
-
Requires-Dist: sentence-transformers==2.6.1; extra == 'dev'
|
|
79
84
|
Requires-Dist: types-requests==2.31.0.20240106; extra == 'dev'
|
|
80
85
|
Requires-Dist: uvicorn==0.35.0; extra == 'dev'
|
|
86
|
+
Provides-Extra: dev-gemini
|
|
87
|
+
Requires-Dist: llama-index-llms-gemini==0.6.0; extra == 'dev-gemini'
|
|
88
|
+
Provides-Extra: dev-strands
|
|
89
|
+
Requires-Dist: strands-agents-tools==0.2.10; extra == 'dev-strands'
|
|
90
|
+
Requires-Dist: strands-agents==1.11.0; extra == 'dev-strands'
|
|
91
|
+
Provides-Extra: dev-tranformers
|
|
92
|
+
Requires-Dist: sentence-transformers==3.3.0; extra == 'dev-tranformers'
|
|
81
93
|
Description-Content-Type: text/markdown
|
|
82
94
|
|
|
83
95
|
# Monocle Apptrace
|
|
@@ -10,7 +10,7 @@ commands = [
|
|
|
10
10
|
|
|
11
11
|
[project]
|
|
12
12
|
name = "monocle_apptrace"
|
|
13
|
-
version = "0.
|
|
13
|
+
version = "0.7.0"
|
|
14
14
|
authors = [
|
|
15
15
|
{ name="Okahu Inc.", email="okahu-pypi@okahu.ai" },
|
|
16
16
|
]
|
|
@@ -26,17 +26,18 @@ classifiers = [
|
|
|
26
26
|
dependencies = [
|
|
27
27
|
'requests',
|
|
28
28
|
'wrapt>=1.14.0',
|
|
29
|
+
'rfc3986>=2.0.0',
|
|
29
30
|
'opentelemetry-api>=1.21.0',
|
|
30
31
|
'opentelemetry-sdk>=1.21.0',
|
|
31
32
|
'opentelemetry-instrumentation',
|
|
32
33
|
]
|
|
33
34
|
|
|
34
35
|
[tool.pytest.ini_options]
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
log_cli = true
|
|
37
|
+
log_cli_level = "INFO"
|
|
37
38
|
# Enable file logging
|
|
38
|
-
log_file = "traces.log"
|
|
39
|
-
log_file_level = "INFO"
|
|
39
|
+
#log_file = "traces.log"
|
|
40
|
+
#log_file_level = "INFO"
|
|
40
41
|
log_format = "%(asctime)s %(levelname)s %(pathname)s:%(lineno)d %(message)s"
|
|
41
42
|
log_date_format = "%Y-%m-%d %H:%M:%S"
|
|
42
43
|
|
|
@@ -44,8 +45,27 @@ pythonpath = [
|
|
|
44
45
|
"src",
|
|
45
46
|
"tests"
|
|
46
47
|
]
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
|
|
49
|
+
# Simple ignore patterns - uncomment lines to ignore specific tests
|
|
50
|
+
# Just uncomment the patterns you want to ignore:
|
|
51
|
+
|
|
52
|
+
#ignore = [
|
|
53
|
+
# "tests/integration/", # Ignore ALL integration tests
|
|
54
|
+
# "tests/unit/", # Ignore ALL unit tests
|
|
55
|
+
#]
|
|
56
|
+
|
|
57
|
+
# Or ignore specific test files/patterns:
|
|
58
|
+
#ignore = [
|
|
59
|
+
# "tests/integration/test_langchain_bedrock_sample.py",
|
|
60
|
+
# "tests/integration/test_anthropic_*.py",
|
|
61
|
+
# "tests/integration/test_azure_*.py",
|
|
62
|
+
# "tests/integration/test_openai_*.py",
|
|
63
|
+
# "tests/unit/*_processor_test.py",
|
|
64
|
+
#]
|
|
65
|
+
|
|
66
|
+
# Test discovery patterns
|
|
67
|
+
testpaths = [
|
|
68
|
+
"tests"
|
|
49
69
|
]
|
|
50
70
|
|
|
51
71
|
[project.optional-dependencies]
|
|
@@ -59,13 +79,13 @@ dev = [
|
|
|
59
79
|
'langchain-chroma==0.2.4',
|
|
60
80
|
'langchain-community==0.3.24',
|
|
61
81
|
'langchain==0.3.25',
|
|
62
|
-
'datasets==
|
|
82
|
+
'datasets==4.3.0',
|
|
63
83
|
'numpy==1.26.4',
|
|
64
84
|
'types-requests==2.31.0.20240106',
|
|
65
85
|
'InstructorEmbedding==1.0.1',
|
|
66
|
-
'sentence-transformers==2.6.1',
|
|
67
86
|
'faiss-cpu==1.8.0',
|
|
68
87
|
'pytest==8.3.5',
|
|
88
|
+
'pytest-venv',
|
|
69
89
|
'llama-index==0.13.0',
|
|
70
90
|
'llama-index-llms-openai==0.5.0',
|
|
71
91
|
'llama-index-tools-mcp==0.3.0',
|
|
@@ -77,7 +97,7 @@ dev = [
|
|
|
77
97
|
'mistral-haystack==0.0.2',
|
|
78
98
|
'langchain-aws==0.2.23',
|
|
79
99
|
'azure-storage-blob==12.22.0', # this is for blob exporter
|
|
80
|
-
'boto3==1.
|
|
100
|
+
'boto3==1.39.0', # this is for aws exporter
|
|
81
101
|
'llama-index-vector-stores-opensearch==0.6.0',
|
|
82
102
|
'haystack-ai==2.3.0',
|
|
83
103
|
'llama-index-llms-azure-openai==0.4.0',
|
|
@@ -109,11 +129,28 @@ dev = [
|
|
|
109
129
|
'google-generativeai==0.8.5',
|
|
110
130
|
'openai-agents==0.2.6',
|
|
111
131
|
'mistralai==1.9.9',
|
|
112
|
-
'huggingface_hub==0.35.3'
|
|
132
|
+
'huggingface_hub==0.35.3',
|
|
133
|
+
'litellm==1.77.5',
|
|
134
|
+
'google-ai-haystack',
|
|
135
|
+
'crewai==0.95.0'
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
dev_tranformers = [
|
|
139
|
+
'sentence-transformers==3.3.0'
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
dev_gemini = [
|
|
143
|
+
'llama-index-llms-gemini==0.6.0'
|
|
144
|
+
]
|
|
145
|
+
|
|
146
|
+
dev_strands = [
|
|
147
|
+
'strands-agents==1.11.0',
|
|
148
|
+
'strands-agents-tools==0.2.10'
|
|
113
149
|
]
|
|
114
150
|
|
|
115
151
|
azure = [
|
|
116
152
|
'azure-storage-blob==12.22.0',
|
|
153
|
+
'azure-ai-inference'
|
|
117
154
|
]
|
|
118
155
|
|
|
119
156
|
aws = [
|
{monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/exporters/aws/s3_exporter.py
RENAMED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import os
|
|
2
|
-
import time
|
|
3
|
-
import random
|
|
4
2
|
import datetime
|
|
5
3
|
import logging
|
|
6
4
|
import asyncio
|
|
@@ -15,12 +13,14 @@ from botocore.exceptions import (
|
|
|
15
13
|
)
|
|
16
14
|
from opentelemetry.sdk.trace import ReadableSpan
|
|
17
15
|
from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult
|
|
18
|
-
from monocle_apptrace.exporters.base_exporter import SpanExporterBase
|
|
16
|
+
from monocle_apptrace.exporters.base_exporter import SpanExporterBase, format_trace_id_without_0x
|
|
19
17
|
from monocle_apptrace.exporters.exporter_processor import ExportTaskProcessor
|
|
20
|
-
from typing import Sequence, Optional
|
|
18
|
+
from typing import Sequence, Optional, Dict, List, Tuple
|
|
21
19
|
import json
|
|
22
20
|
logger = logging.getLogger(__name__)
|
|
23
21
|
|
|
22
|
+
HANDLE_TIMEOUT_SECONDS = 60
|
|
23
|
+
|
|
24
24
|
class S3SpanExporter(SpanExporterBase):
|
|
25
25
|
def __init__(self, bucket_name=None, region_name=None, task_processor: Optional[ExportTaskProcessor] = None):
|
|
26
26
|
super().__init__()
|
|
@@ -29,6 +29,8 @@ class S3SpanExporter(SpanExporterBase):
|
|
|
29
29
|
DEFAULT_TIME_FORMAT = "%Y-%m-%d__%H.%M.%S"
|
|
30
30
|
self.max_batch_size = 500
|
|
31
31
|
self.export_interval = 1
|
|
32
|
+
# Dictionary to store spans by trace_id: {trace_id: (spans_list, creation_time, has_root_span)}
|
|
33
|
+
self.trace_spans: Dict[int, Tuple[List[ReadableSpan], datetime.datetime, bool]] = {}
|
|
32
34
|
if(os.getenv('MONOCLE_AWS_ACCESS_KEY_ID') and os.getenv('MONOCLE_AWS_SECRET_ACCESS_KEY')):
|
|
33
35
|
self.s3_client = boto3.client(
|
|
34
36
|
's3',
|
|
@@ -46,8 +48,6 @@ class S3SpanExporter(SpanExporterBase):
|
|
|
46
48
|
self.bucket_name = bucket_name or os.getenv('MONOCLE_S3_BUCKET_NAME','default-bucket')
|
|
47
49
|
self.file_prefix = os.getenv('MONOCLE_S3_KEY_PREFIX', DEFAULT_FILE_PREFIX)
|
|
48
50
|
self.time_format = DEFAULT_TIME_FORMAT
|
|
49
|
-
self.export_queue = []
|
|
50
|
-
self.last_export_time = time.time()
|
|
51
51
|
self.task_processor = task_processor
|
|
52
52
|
if self.task_processor is not None:
|
|
53
53
|
self.task_processor.start()
|
|
@@ -92,6 +92,47 @@ class S3SpanExporter(SpanExporterBase):
|
|
|
92
92
|
logger.error(f"Type error while checking bucket existence: {e}")
|
|
93
93
|
raise e
|
|
94
94
|
|
|
95
|
+
def _cleanup_expired_traces(self) -> None:
|
|
96
|
+
"""Upload and remove traces that have exceeded the timeout."""
|
|
97
|
+
current_time = datetime.datetime.now()
|
|
98
|
+
expired_trace_ids = []
|
|
99
|
+
|
|
100
|
+
for trace_id, (spans, creation_time, _) in self.trace_spans.items():
|
|
101
|
+
if (current_time - creation_time).total_seconds() > HANDLE_TIMEOUT_SECONDS:
|
|
102
|
+
expired_trace_ids.append(trace_id)
|
|
103
|
+
|
|
104
|
+
for trace_id in expired_trace_ids:
|
|
105
|
+
self._upload_trace(trace_id)
|
|
106
|
+
|
|
107
|
+
def _add_spans_to_trace(self, trace_id: int, spans: List[ReadableSpan], has_root: bool = False) -> None:
|
|
108
|
+
"""Add spans to a trace buffer, creating it if needed."""
|
|
109
|
+
if trace_id in self.trace_spans:
|
|
110
|
+
existing_spans, creation_time, existing_root = self.trace_spans[trace_id]
|
|
111
|
+
existing_spans.extend(spans)
|
|
112
|
+
has_root = has_root or existing_root
|
|
113
|
+
self.trace_spans[trace_id] = (existing_spans, creation_time, has_root)
|
|
114
|
+
else:
|
|
115
|
+
self.trace_spans[trace_id] = (spans.copy(), datetime.datetime.now(), has_root)
|
|
116
|
+
|
|
117
|
+
def _upload_trace(self, trace_id: int) -> None:
|
|
118
|
+
"""Upload a specific trace to S3 and remove it from the buffer."""
|
|
119
|
+
if trace_id not in self.trace_spans:
|
|
120
|
+
return
|
|
121
|
+
|
|
122
|
+
spans, _, _ = self.trace_spans[trace_id]
|
|
123
|
+
if len(spans) == 0:
|
|
124
|
+
del self.trace_spans[trace_id]
|
|
125
|
+
return
|
|
126
|
+
|
|
127
|
+
serialized_data = self.__serialize_spans(spans)
|
|
128
|
+
if serialized_data:
|
|
129
|
+
try:
|
|
130
|
+
self.__upload_to_s3_with_trace_id(serialized_data, trace_id)
|
|
131
|
+
except Exception as e:
|
|
132
|
+
logger.error(f"Failed to upload trace {format_trace_id_without_0x(trace_id)}: {e}")
|
|
133
|
+
|
|
134
|
+
del self.trace_spans[trace_id]
|
|
135
|
+
|
|
95
136
|
def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
|
|
96
137
|
"""Synchronous export method that internally handles async logic."""
|
|
97
138
|
try:
|
|
@@ -106,18 +147,44 @@ class S3SpanExporter(SpanExporterBase):
|
|
|
106
147
|
async def __export_async(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
|
|
107
148
|
try:
|
|
108
149
|
logger.info(f"__export_async {len(spans)} spans to S3.")
|
|
109
|
-
|
|
150
|
+
|
|
151
|
+
# Cleanup expired traces first
|
|
152
|
+
self._cleanup_expired_traces()
|
|
153
|
+
|
|
154
|
+
# Group spans by trace_id
|
|
155
|
+
spans_by_trace = {}
|
|
156
|
+
root_span_traces = set()
|
|
157
|
+
|
|
110
158
|
for span in spans:
|
|
111
|
-
self.
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
159
|
+
if self.skip_export(span):
|
|
160
|
+
continue
|
|
161
|
+
|
|
162
|
+
trace_id = span.context.trace_id
|
|
163
|
+
if trace_id not in spans_by_trace:
|
|
164
|
+
spans_by_trace[trace_id] = []
|
|
165
|
+
spans_by_trace[trace_id].append(span)
|
|
166
|
+
|
|
167
|
+
# Check if this span is a root span (no parent)
|
|
168
|
+
if not span.parent:
|
|
169
|
+
root_span_traces.add(trace_id)
|
|
170
|
+
|
|
171
|
+
# Add spans to their respective trace buffers
|
|
172
|
+
for trace_id, trace_spans in spans_by_trace.items():
|
|
173
|
+
has_root = trace_id in root_span_traces
|
|
174
|
+
self._add_spans_to_trace(trace_id, trace_spans, has_root)
|
|
175
|
+
|
|
176
|
+
# Upload complete traces (those with root spans)
|
|
177
|
+
for trace_id in root_span_traces:
|
|
178
|
+
if self.task_processor is not None and callable(getattr(self.task_processor, 'queue_task', None)):
|
|
179
|
+
# Queue the upload task
|
|
180
|
+
if trace_id in self.trace_spans:
|
|
181
|
+
spans_to_upload, _, _ = self.trace_spans[trace_id]
|
|
182
|
+
serialized_data = self.__serialize_spans(spans_to_upload)
|
|
183
|
+
if serialized_data:
|
|
184
|
+
self.task_processor.queue_task(self.__upload_to_s3_with_trace_id, serialized_data, trace_id, True)
|
|
185
|
+
del self.trace_spans[trace_id]
|
|
186
|
+
else:
|
|
187
|
+
self._upload_trace(trace_id)
|
|
121
188
|
|
|
122
189
|
return SpanExportResult.SUCCESS
|
|
123
190
|
except Exception as e:
|
|
@@ -140,44 +207,35 @@ class S3SpanExporter(SpanExporterBase):
|
|
|
140
207
|
return ndjson_data
|
|
141
208
|
except Exception as e:
|
|
142
209
|
logger.warning(f"Error serializing spans: {e}")
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
async def __export_spans(self):
|
|
146
|
-
if len(self.export_queue) == 0:
|
|
147
|
-
return
|
|
148
|
-
|
|
149
|
-
# Take a batch of spans from the queue
|
|
150
|
-
batch_to_export = self.export_queue[:self.max_batch_size]
|
|
151
|
-
serialized_data = self.__serialize_spans(batch_to_export)
|
|
152
|
-
self.export_queue = self.export_queue[self.max_batch_size:]
|
|
153
|
-
# to calculate is_root_span loop over each span in batch_to_export and check if parent id is none or null
|
|
154
|
-
is_root_span = any(not span.parent for span in batch_to_export)
|
|
155
|
-
logger.info(f"Exporting {len(batch_to_export)} spans to S3 is_root_span : {is_root_span}.")
|
|
156
|
-
if self.task_processor is not None and callable(getattr(self.task_processor, 'queue_task', None)):
|
|
157
|
-
self.task_processor.queue_task(self.__upload_to_s3, serialized_data, is_root_span)
|
|
158
|
-
else:
|
|
159
|
-
try:
|
|
160
|
-
self.__upload_to_s3(serialized_data)
|
|
161
|
-
except Exception as e:
|
|
162
|
-
logger.error(f"Failed to upload span batch: {e}")
|
|
210
|
+
return ""
|
|
163
211
|
|
|
164
212
|
@SpanExporterBase.retry_with_backoff(exceptions=(EndpointConnectionError, ConnectionClosedError, ReadTimeoutError, ConnectTimeoutError))
|
|
165
|
-
def
|
|
213
|
+
def __upload_to_s3_with_trace_id(self, span_data_batch: str, trace_id: int):
|
|
214
|
+
"""Upload spans for a specific trace to S3 with trace ID in filename."""
|
|
166
215
|
current_time = datetime.datetime.now().strftime(self.time_format)
|
|
167
216
|
prefix = self.file_prefix + os.environ.get('MONOCLE_S3_KEY_PREFIX_CURRENT', '')
|
|
168
|
-
file_name = f"{prefix}{current_time}.ndjson"
|
|
217
|
+
file_name = f"{prefix}{current_time}_{format_trace_id_without_0x(trace_id)}.ndjson"
|
|
169
218
|
self.s3_client.put_object(
|
|
170
219
|
Bucket=self.bucket_name,
|
|
171
220
|
Key=file_name,
|
|
172
221
|
Body=span_data_batch
|
|
173
222
|
)
|
|
174
|
-
logger.debug(f"
|
|
223
|
+
logger.debug(f"Trace {format_trace_id_without_0x(trace_id)} uploaded to AWS S3 as {file_name}.")
|
|
175
224
|
|
|
176
225
|
async def force_flush(self, timeout_millis: int = 30000) -> bool:
|
|
177
|
-
|
|
226
|
+
"""Flush all pending traces to S3."""
|
|
227
|
+
trace_ids_to_upload = list(self.trace_spans.keys())
|
|
228
|
+
for trace_id in trace_ids_to_upload:
|
|
229
|
+
self._upload_trace(trace_id)
|
|
178
230
|
return True
|
|
179
231
|
|
|
180
232
|
def shutdown(self) -> None:
|
|
233
|
+
"""Upload all pending traces and shutdown."""
|
|
234
|
+
# Upload all remaining traces
|
|
235
|
+
trace_ids_to_upload = list(self.trace_spans.keys())
|
|
236
|
+
for trace_id in trace_ids_to_upload:
|
|
237
|
+
self._upload_trace(trace_id)
|
|
238
|
+
|
|
181
239
|
if hasattr(self, 'task_processor') and self.task_processor is not None:
|
|
182
240
|
self.task_processor.stop()
|
|
183
241
|
logger.info("S3SpanExporter has been shut down.")
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import datetime
|
|
3
|
+
import logging
|
|
4
|
+
import asyncio
|
|
5
|
+
from azure.storage.blob import BlobServiceClient, BlobClient, ContainerClient
|
|
6
|
+
from azure.core.exceptions import ResourceNotFoundError, ClientAuthenticationError, ServiceRequestError
|
|
7
|
+
from opentelemetry.sdk.trace import ReadableSpan
|
|
8
|
+
from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult
|
|
9
|
+
from typing import Sequence, Optional, Dict, List, Tuple
|
|
10
|
+
from monocle_apptrace.exporters.base_exporter import SpanExporterBase, format_trace_id_without_0x
|
|
11
|
+
from monocle_apptrace.exporters.exporter_processor import ExportTaskProcessor
|
|
12
|
+
import json
|
|
13
|
+
from monocle_apptrace.instrumentation.common.constants import MONOCLE_SDK_VERSION
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
HANDLE_TIMEOUT_SECONDS = 60 # 1 minute timeout for orphaned traces
|
|
17
|
+
|
|
18
|
+
class AzureBlobSpanExporter(SpanExporterBase):
|
|
19
|
+
def __init__(self, connection_string=None, container_name=None, task_processor: Optional[ExportTaskProcessor] = None):
|
|
20
|
+
super().__init__()
|
|
21
|
+
DEFAULT_FILE_PREFIX = "monocle_trace_"
|
|
22
|
+
DEFAULT_TIME_FORMAT = "%Y-%m-%d_%H.%M.%S"
|
|
23
|
+
self.max_batch_size = 500
|
|
24
|
+
self.export_interval = 1
|
|
25
|
+
# Dictionary to store spans by trace_id: {trace_id: (spans_list, creation_time, has_root_span)}
|
|
26
|
+
self.trace_spans: Dict[int, Tuple[List[ReadableSpan], datetime.datetime, bool]] = {}
|
|
27
|
+
# Use default values if none are provided
|
|
28
|
+
if not connection_string:
|
|
29
|
+
connection_string = os.getenv('MONOCLE_BLOB_CONNECTION_STRING')
|
|
30
|
+
if not connection_string:
|
|
31
|
+
raise ValueError("Azure Storage connection string is not provided or set in environment variables.")
|
|
32
|
+
|
|
33
|
+
if not container_name:
|
|
34
|
+
container_name = os.getenv('MONOCLE_BLOB_CONTAINER_NAME', 'default-container')
|
|
35
|
+
|
|
36
|
+
self.blob_service_client = BlobServiceClient.from_connection_string(connection_string)
|
|
37
|
+
self.container_name = container_name
|
|
38
|
+
self.file_prefix = DEFAULT_FILE_PREFIX
|
|
39
|
+
self.time_format = DEFAULT_TIME_FORMAT
|
|
40
|
+
|
|
41
|
+
# Check if container exists or create it
|
|
42
|
+
if not self.__container_exists(container_name):
|
|
43
|
+
try:
|
|
44
|
+
self.blob_service_client.create_container(container_name)
|
|
45
|
+
logger.info(f"Container {container_name} created successfully.")
|
|
46
|
+
except Exception as e:
|
|
47
|
+
logger.error(f"Error creating container {container_name}: {e}")
|
|
48
|
+
raise e
|
|
49
|
+
|
|
50
|
+
self.task_processor = task_processor
|
|
51
|
+
if self.task_processor is not None:
|
|
52
|
+
self.task_processor.start()
|
|
53
|
+
|
|
54
|
+
def __container_exists(self, container_name):
|
|
55
|
+
try:
|
|
56
|
+
container_client = self.blob_service_client.get_container_client(container_name)
|
|
57
|
+
container_client.get_container_properties()
|
|
58
|
+
return True
|
|
59
|
+
except ResourceNotFoundError:
|
|
60
|
+
logger.error(f"Container {container_name} not found (404).")
|
|
61
|
+
return False
|
|
62
|
+
except ClientAuthenticationError:
|
|
63
|
+
logger.error(f"Access to container {container_name} is forbidden (403).")
|
|
64
|
+
raise PermissionError(f"Access to container {container_name} is forbidden.")
|
|
65
|
+
except Exception as e:
|
|
66
|
+
logger.error(f"Unexpected error when checking if container {container_name} exists: {e}")
|
|
67
|
+
raise e
|
|
68
|
+
|
|
69
|
+
def _cleanup_expired_traces(self) -> None:
|
|
70
|
+
"""Upload and remove traces that have exceeded the timeout."""
|
|
71
|
+
current_time = datetime.datetime.now()
|
|
72
|
+
expired_trace_ids = []
|
|
73
|
+
|
|
74
|
+
for trace_id, (spans, creation_time, _) in self.trace_spans.items():
|
|
75
|
+
if (current_time - creation_time).total_seconds() > HANDLE_TIMEOUT_SECONDS:
|
|
76
|
+
expired_trace_ids.append(trace_id)
|
|
77
|
+
|
|
78
|
+
for trace_id in expired_trace_ids:
|
|
79
|
+
self._upload_trace(trace_id)
|
|
80
|
+
|
|
81
|
+
def _add_spans_to_trace(self, trace_id: int, spans: List[ReadableSpan], has_root: bool = False) -> None:
|
|
82
|
+
"""Add spans to a trace buffer, creating it if needed."""
|
|
83
|
+
if trace_id in self.trace_spans:
|
|
84
|
+
existing_spans, creation_time, existing_root = self.trace_spans[trace_id]
|
|
85
|
+
existing_spans.extend(spans)
|
|
86
|
+
has_root = has_root or existing_root
|
|
87
|
+
self.trace_spans[trace_id] = (existing_spans, creation_time, has_root)
|
|
88
|
+
else:
|
|
89
|
+
self.trace_spans[trace_id] = (spans.copy(), datetime.datetime.now(), has_root)
|
|
90
|
+
|
|
91
|
+
def _upload_trace(self, trace_id: int) -> None:
|
|
92
|
+
"""Upload a specific trace to Azure Blob and remove it from the buffer."""
|
|
93
|
+
if trace_id not in self.trace_spans:
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
spans, _, _ = self.trace_spans[trace_id]
|
|
97
|
+
if len(spans) == 0:
|
|
98
|
+
del self.trace_spans[trace_id]
|
|
99
|
+
return
|
|
100
|
+
|
|
101
|
+
serialized_data = self.__serialize_spans(spans)
|
|
102
|
+
if serialized_data:
|
|
103
|
+
try:
|
|
104
|
+
self.__upload_to_blob_with_trace_id(serialized_data, trace_id)
|
|
105
|
+
except Exception as e:
|
|
106
|
+
logger.error(f"Failed to upload trace {format_trace_id_without_0x(trace_id)}: {e}")
|
|
107
|
+
|
|
108
|
+
del self.trace_spans[trace_id]
|
|
109
|
+
|
|
110
|
+
def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
|
|
111
|
+
"""Synchronous export method that internally handles async logic."""
|
|
112
|
+
try:
|
|
113
|
+
# Run the asynchronous export logic in an event loop
|
|
114
|
+
asyncio.run(self._export_async(spans))
|
|
115
|
+
return SpanExportResult.SUCCESS
|
|
116
|
+
except Exception as e:
|
|
117
|
+
logger.error(f"Error exporting spans: {e}")
|
|
118
|
+
return SpanExportResult.FAILURE
|
|
119
|
+
|
|
120
|
+
async def _export_async(self, spans: Sequence[ReadableSpan]):
|
|
121
|
+
"""The actual async export logic is run here."""
|
|
122
|
+
try:
|
|
123
|
+
# Cleanup expired traces first
|
|
124
|
+
self._cleanup_expired_traces()
|
|
125
|
+
|
|
126
|
+
# Group spans by trace_id
|
|
127
|
+
spans_by_trace = {}
|
|
128
|
+
root_span_traces = set()
|
|
129
|
+
|
|
130
|
+
for span in spans:
|
|
131
|
+
# Azure blob library has a check to generate it's own span if OpenTelemetry is loaded and Azure trace package is installed (just pip install azure-trace-opentelemetry)
|
|
132
|
+
# With Monocle,OpenTelemetry is always loaded. If the Azure trace package is installed, then it triggers the blob trace generation on every blob operation.
|
|
133
|
+
# Thus, the Monocle span write ends up generating a blob span which again comes back to the exporter .. and would result in an infinite loop.
|
|
134
|
+
# To avoid this, we check if the span has the Monocle SDK version attribute and skip it if it doesn't. That way the blob span genearted by Azure library are not exported.
|
|
135
|
+
if self.skip_export(span):
|
|
136
|
+
continue
|
|
137
|
+
|
|
138
|
+
trace_id = span.context.trace_id
|
|
139
|
+
if trace_id not in spans_by_trace:
|
|
140
|
+
spans_by_trace[trace_id] = []
|
|
141
|
+
spans_by_trace[trace_id].append(span)
|
|
142
|
+
|
|
143
|
+
# Check if this span is a root span (no parent)
|
|
144
|
+
if not span.parent:
|
|
145
|
+
root_span_traces.add(trace_id)
|
|
146
|
+
|
|
147
|
+
# Add spans to their respective trace buffers
|
|
148
|
+
for trace_id, trace_spans in spans_by_trace.items():
|
|
149
|
+
has_root = trace_id in root_span_traces
|
|
150
|
+
self._add_spans_to_trace(trace_id, trace_spans, has_root)
|
|
151
|
+
|
|
152
|
+
# Upload complete traces (those with root spans)
|
|
153
|
+
for trace_id in root_span_traces:
|
|
154
|
+
if self.task_processor is not None and callable(getattr(self.task_processor, 'queue_task', None)):
|
|
155
|
+
# Queue the upload task
|
|
156
|
+
if trace_id in self.trace_spans:
|
|
157
|
+
spans_to_upload, _, _ = self.trace_spans[trace_id]
|
|
158
|
+
serialized_data = self.__serialize_spans(spans_to_upload)
|
|
159
|
+
if serialized_data:
|
|
160
|
+
self.task_processor.queue_task(self.__upload_to_blob_with_trace_id, serialized_data, trace_id)
|
|
161
|
+
del self.trace_spans[trace_id]
|
|
162
|
+
else:
|
|
163
|
+
self._upload_trace(trace_id)
|
|
164
|
+
except Exception as e:
|
|
165
|
+
logger.error(f"Error in _export_async: {e}")
|
|
166
|
+
|
|
167
|
+
def __serialize_spans(self, spans: Sequence[ReadableSpan]) -> str:
|
|
168
|
+
try:
|
|
169
|
+
valid_json_list = []
|
|
170
|
+
for span in spans:
|
|
171
|
+
try:
|
|
172
|
+
valid_json_list.append(span.to_json(indent=0).replace("\n", ""))
|
|
173
|
+
except json.JSONDecodeError as e:
|
|
174
|
+
logger.warning(f"Invalid JSON format in span data: {span.context.span_id}. Error: {e}")
|
|
175
|
+
continue
|
|
176
|
+
|
|
177
|
+
ndjson_data = "\n".join(valid_json_list) + "\n"
|
|
178
|
+
return ndjson_data
|
|
179
|
+
except Exception as e:
|
|
180
|
+
logger.warning(f"Error serializing spans: {e}")
|
|
181
|
+
return ""
|
|
182
|
+
|
|
183
|
+
@SpanExporterBase.retry_with_backoff(exceptions=(ResourceNotFoundError, ClientAuthenticationError, ServiceRequestError))
|
|
184
|
+
def __upload_to_blob_with_trace_id(self, span_data_batch: str, trace_id: int):
|
|
185
|
+
"""Upload spans for a specific trace to Azure Blob with trace ID in filename."""
|
|
186
|
+
current_time = datetime.datetime.now().strftime(self.time_format)
|
|
187
|
+
file_name = f"{self.file_prefix}{current_time}_{format_trace_id_without_0x(trace_id)}.ndjson"
|
|
188
|
+
blob_client = self.blob_service_client.get_blob_client(container=self.container_name, blob=file_name)
|
|
189
|
+
blob_client.upload_blob(span_data_batch, overwrite=True)
|
|
190
|
+
logger.debug(f"Trace {format_trace_id_without_0x(trace_id)} uploaded to Azure Blob Storage as {file_name}.")
|
|
191
|
+
|
|
192
|
+
async def force_flush(self, timeout_millis: int = 30000) -> bool:
|
|
193
|
+
"""Flush all pending traces to Azure Blob."""
|
|
194
|
+
trace_ids_to_upload = list(self.trace_spans.keys())
|
|
195
|
+
for trace_id in trace_ids_to_upload:
|
|
196
|
+
self._upload_trace(trace_id)
|
|
197
|
+
return True
|
|
198
|
+
|
|
199
|
+
def shutdown(self) -> None:
|
|
200
|
+
"""Upload all pending traces and shutdown."""
|
|
201
|
+
# Upload all remaining traces
|
|
202
|
+
trace_ids_to_upload = list(self.trace_spans.keys())
|
|
203
|
+
for trace_id in trace_ids_to_upload:
|
|
204
|
+
self._upload_trace(trace_id)
|
|
205
|
+
|
|
206
|
+
if hasattr(self, 'task_processor') and self.task_processor is not None:
|
|
207
|
+
self.task_processor.stop()
|
|
208
|
+
logger.info("AzureBlobSpanExporter has been shut down.")
|
{monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/exporters/base_exporter.py
RENAMED
|
@@ -51,4 +51,13 @@ class SpanExporterBase(ABC):
|
|
|
51
51
|
|
|
52
52
|
return wrapper
|
|
53
53
|
|
|
54
|
-
return decorator
|
|
54
|
+
return decorator
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def format_trace_id_without_0x(trace_id: int) -> str:
|
|
58
|
+
"""Format trace_id as 32-character lowercase hex string without 0x prefix."""
|
|
59
|
+
return f"{trace_id:032x}"
|
|
60
|
+
|
|
61
|
+
def format_span_id_without_0x(span_id: int) -> str:
|
|
62
|
+
"""Format span_id as 16-character lowercase hex string without 0x prefix."""
|
|
63
|
+
return f"{span_id:016x}"
|
{monocle_apptrace-0.6.0 → monocle_apptrace-0.7.0}/src/monocle_apptrace/exporters/file_exporter.py
RENAMED
|
@@ -8,7 +8,7 @@ from typing import Optional, Callable, Sequence, Dict, Tuple
|
|
|
8
8
|
from opentelemetry.sdk.trace import ReadableSpan
|
|
9
9
|
from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult
|
|
10
10
|
from opentelemetry.sdk.resources import SERVICE_NAME
|
|
11
|
-
from monocle_apptrace.exporters.base_exporter import SpanExporterBase
|
|
11
|
+
from monocle_apptrace.exporters.base_exporter import SpanExporterBase, format_trace_id_without_0x
|
|
12
12
|
from monocle_apptrace.exporters.exporter_processor import ExportTaskProcessor
|
|
13
13
|
|
|
14
14
|
DEFAULT_FILE_PREFIX:str = "monocle_trace_"
|
|
@@ -25,7 +25,7 @@ class FileSpanExporter(SpanExporterBase):
|
|
|
25
25
|
time_format = DEFAULT_TIME_FORMAT,
|
|
26
26
|
formatter: Callable[
|
|
27
27
|
[ReadableSpan], str
|
|
28
|
-
] = lambda span: span.to_json()
|
|
28
|
+
] = lambda span: span.to_json(indent = 4)
|
|
29
29
|
+ linesep,
|
|
30
30
|
task_processor: Optional[ExportTaskProcessor] = None
|
|
31
31
|
):
|
|
@@ -80,7 +80,7 @@ class FileSpanExporter(SpanExporterBase):
|
|
|
80
80
|
|
|
81
81
|
# Create new handle
|
|
82
82
|
file_path = path.join(self.output_path,
|
|
83
|
-
self.file_prefix + service_name + "_" +
|
|
83
|
+
self.file_prefix + service_name + "_" + format_trace_id_without_0x(trace_id) + "_"
|
|
84
84
|
+ datetime.now().strftime(self.time_format) + ".json")
|
|
85
85
|
|
|
86
86
|
try:
|
|
@@ -63,13 +63,6 @@ class OkahuSpanExporter(SpanExporterBase):
|
|
|
63
63
|
continue
|
|
64
64
|
# create a object from serialized span
|
|
65
65
|
obj = json.loads(span.to_json())
|
|
66
|
-
if obj["parent_id"] is None:
|
|
67
|
-
obj["parent_id"] = "None"
|
|
68
|
-
else:
|
|
69
|
-
obj["parent_id"] = remove_0x_from_start(obj["parent_id"])
|
|
70
|
-
if obj["context"] is not None:
|
|
71
|
-
obj["context"]["trace_id"] = remove_0x_from_start(obj["context"]["trace_id"])
|
|
72
|
-
obj["context"]["span_id"] = remove_0x_from_start(obj["context"]["span_id"])
|
|
73
66
|
span_list["batch"].append(obj)
|
|
74
67
|
|
|
75
68
|
# Calculate is_root_span by checking if any span has no parent
|
|
@@ -110,11 +103,4 @@ class OkahuSpanExporter(SpanExporterBase):
|
|
|
110
103
|
self._closed = True
|
|
111
104
|
|
|
112
105
|
def force_flush(self, timeout_millis: int = 30000) -> bool:
|
|
113
|
-
return True
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
# only removes the first occurrence of 0x from the string
|
|
117
|
-
def remove_0x_from_start(my_str: str):
|
|
118
|
-
if my_str.startswith("0x"):
|
|
119
|
-
return my_str.replace("0x", "", 1)
|
|
120
|
-
return my_str
|
|
106
|
+
return True
|