tracecast 0.2.5__tar.gz → 0.2.7__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.
- {tracecast-0.2.5/tracecast.egg-info → tracecast-0.2.7}/PKG-INFO +1 -1
- {tracecast-0.2.5 → tracecast-0.2.7}/pyproject.toml +1 -1
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_cost_calculator.py +51 -1
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_dashboard_pushdown.py +46 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/core/cost_calculator.py +26 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/dashboard/reader.py +22 -6
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/dashboard/router.py +1 -1
- tracecast-0.2.5/tracecast/dashboard/static/assets/index-CPXZquql.js → tracecast-0.2.7/tracecast/dashboard/static/assets/index-BMIlEmLS.js +28 -28
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/dashboard/static/index.html +1 -1
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/instrumentors/openai_inst.py +165 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/models/span.py +5 -3
- {tracecast-0.2.5 → tracecast-0.2.7/tracecast.egg-info}/PKG-INFO +1 -1
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast.egg-info/SOURCES.txt +1 -1
- {tracecast-0.2.5 → tracecast-0.2.7}/LICENSE +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/README.md +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/setup.cfg +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_aggregator_graph.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_context_propagation.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_dashboard_mount.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_dashboard_sessions.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_decorators.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_e2e_langgraph.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_exporters_db.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_integration_frameworks.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_integration_langchain.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_json_exporter.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_langchain_callback.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_llm_wrappers.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_logging.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_mongo_exporter.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_prompt_dashboard.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_prompts.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_roundtrip.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_schema_v2.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_score.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_score_dashboard.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_scoring_api.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_serve.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_span.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_streaming.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_token_counter.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_trace.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_trace_span.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tests/test_tracer.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/__init__.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/core/__init__.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/core/logger.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/core/scoring.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/core/token_counter.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/core/tracer.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/dashboard/__init__.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/dashboard/aggregator.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/dashboard/asgi_middleware.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/dashboard/blueprint.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/dashboard/eval_reader.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/dashboard/prompt_reader.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/dashboard/score_reader.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/dashboard/standalone.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/dashboard/static/assets/index-B07hiBI2.js +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/dashboard/static/assets/index-CY5YOA8F.js +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/dashboard/static/assets/index-DllJJzmE.css +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/dashboard/static/assets/index-Dt0awpJJ.js +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/decorators.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/eval/__init__.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/eval/cli.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/eval/compare.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/eval/dataset.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/eval/decorator.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/eval/judge.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/eval/metrics.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/eval/models.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/eval/online.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/eval/runner.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/eval/scorers.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/exporters/__init__.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/exporters/_eval_store.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/exporters/base.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/exporters/dict_exporter.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/exporters/json_file.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/exporters/mongo.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/exporters/postgres.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/exporters/query.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/instrument.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/instrumentors/__init__.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/instrumentors/_llamaindex_handler.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/instrumentors/_streaming.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/instrumentors/anthropic_inst.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/instrumentors/base.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/instrumentors/crewai_inst.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/instrumentors/gemini_inst.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/instrumentors/langchain_inst.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/instrumentors/llamaindex_inst.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/integrations/__init__.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/integrations/langchain.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/integrations/llm.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/middleware.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/models/__init__.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/models/score.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/models/trace.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/prompts/__init__.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/prompts/client.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/prompts/models.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast/serve.py +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast.egg-info/dependency_links.txt +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast.egg-info/entry_points.txt +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast.egg-info/requires.txt +0 -0
- {tracecast-0.2.5 → tracecast-0.2.7}/tracecast.egg-info/top_level.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import pytest
|
|
2
|
-
from tracecast.core.cost_calculator import calculate_cost, PRICE_TABLE
|
|
2
|
+
from tracecast.core.cost_calculator import calculate_cost, calculate_audio_cost, PRICE_TABLE
|
|
3
3
|
|
|
4
4
|
@pytest.mark.parametrize("model", [
|
|
5
5
|
"gpt-4o", "gpt-4o-mini", "gpt-4-turbo",
|
|
@@ -151,3 +151,53 @@ def test_modelos_sem_suporte_a_cache_nao_tem_chave_cached():
|
|
|
151
151
|
modelos_sem_cache = ["gpt-4-turbo", "gemini-2.5-flash", "llama-4-scout"]
|
|
152
152
|
for model in modelos_sem_cache:
|
|
153
153
|
assert "cached" not in PRICE_TABLE[model], f"{model} nao deveria ter preco de cache"
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
# --- gpt-4.1-nano (bug: ausente da tabela, custo virava $0 silenciosamente) ---
|
|
157
|
+
|
|
158
|
+
def test_gpt_4_1_nano_tem_preco():
|
|
159
|
+
assert "gpt-4.1-nano" in PRICE_TABLE
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def test_calcula_custo_gpt_4_1_nano():
|
|
163
|
+
# $0.10 / $0.40 por 1M tokens = 0.00010 / 0.00040 por 1k
|
|
164
|
+
cost = calculate_cost("gpt-4.1-nano", tokens_in=1000, tokens_out=1000)
|
|
165
|
+
assert abs(cost - (0.00010 + 0.00040)) < 1e-9
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def test_gpt_4_1_nano_cached_e_25_pct_do_input():
|
|
169
|
+
# mesmo padrao dos irmaos gpt-4.1 / gpt-4.1-mini: cached = 25% do input
|
|
170
|
+
entry = PRICE_TABLE["gpt-4.1-nano"]
|
|
171
|
+
assert abs(entry["cached"] - entry["input"] * 0.25) < 1e-9
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
# --- embeddings (bug: nunca precificados, custo $0 mesmo se instrumentados) ---
|
|
175
|
+
|
|
176
|
+
@pytest.mark.parametrize("model,expected_input", [
|
|
177
|
+
("text-embedding-3-small", 0.00002),
|
|
178
|
+
("text-embedding-3-large", 0.00013),
|
|
179
|
+
("text-embedding-ada-002", 0.00010),
|
|
180
|
+
])
|
|
181
|
+
def test_calcula_custo_embeddings(model, expected_input):
|
|
182
|
+
cost = calculate_cost(model, tokens_in=1000, tokens_out=0)
|
|
183
|
+
assert abs(cost - expected_input) < 1e-9
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# --- audio (bug: whisper/tts nunca precificados nem instrumentados) ---
|
|
187
|
+
|
|
188
|
+
def test_calculate_audio_cost_whisper_por_minuto():
|
|
189
|
+
cost = calculate_audio_cost("whisper-1", minutes=2.5)
|
|
190
|
+
assert abs(cost - (2.5 * 0.006)) < 1e-9
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def test_calculate_audio_cost_tts_por_caractere():
|
|
194
|
+
cost = calculate_audio_cost("gpt-4o-mini-tts", chars=1000)
|
|
195
|
+
assert cost > 0
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def test_calculate_audio_cost_modelo_desconhecido_retorna_zero():
|
|
199
|
+
assert calculate_audio_cost("modelo-inexistente", minutes=10) == 0.0
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def test_calculate_audio_cost_sem_uso_retorna_zero():
|
|
203
|
+
assert calculate_audio_cost("whisper-1") == 0.0
|
|
@@ -108,3 +108,49 @@ def test_index_injects_prefix():
|
|
|
108
108
|
resp = client.get("/tc/")
|
|
109
109
|
assert resp.status_code == 200
|
|
110
110
|
assert 'window.__TC_PREFIX__ = "/tc"' in resp.text
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_get_traces_for_metrics_bypasses_max_traces_cap():
|
|
114
|
+
exporter = FakeReadableExporter([_trace(f"t{i}", "p1", i) for i in range(5)])
|
|
115
|
+
reader = TraceReader([exporter], max_traces=2)
|
|
116
|
+
assert len(reader.get_traces_for_metrics()) == 5
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_api_metrics_bypasses_max_traces_cap():
|
|
120
|
+
exporter = FakeReadableExporter([_trace(f"t{i}", "p1", i) for i in range(5)])
|
|
121
|
+
tracer = Tracer(exporters=[exporter])
|
|
122
|
+
app = FastAPI()
|
|
123
|
+
tracer.mount(app, prefix="/tc", max_traces=2)
|
|
124
|
+
client = TestClient(app)
|
|
125
|
+
resp = client.get("/tc/api/metrics", params={"from": "2020-01-01T00:00:00Z", "to": "2030-01-01T00:00:00Z"})
|
|
126
|
+
assert resp.status_code == 200
|
|
127
|
+
assert resp.json()["total_traces"] == 5
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _trace_named_project(trace_id, project_name, offset_min=0):
|
|
131
|
+
base = datetime(2026, 6, 1, tzinfo=timezone.utc) + timedelta(minutes=offset_min)
|
|
132
|
+
t = Trace(trace_id=trace_id, name="req", started_at=base, project_name=project_name)
|
|
133
|
+
t.finished_at = base + timedelta(seconds=1)
|
|
134
|
+
t._finalize()
|
|
135
|
+
return t
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_get_filter_options_bypasses_max_traces_cap():
|
|
139
|
+
# "rare-project" is the oldest trace; a small cap sorted by recency would drop it.
|
|
140
|
+
exporter = FakeReadableExporter([
|
|
141
|
+
_trace_named_project("old", "rare-project", offset_min=0),
|
|
142
|
+
*[_trace_named_project(f"t{i}", "common-project", offset_min=10 + i) for i in range(5)],
|
|
143
|
+
])
|
|
144
|
+
reader = TraceReader([exporter], max_traces=3)
|
|
145
|
+
opts = reader.get_filter_options()
|
|
146
|
+
assert "rare-project" in opts["project_names"]
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def test_get_projects_bypasses_max_traces_cap():
|
|
150
|
+
exporter = FakeReadableExporter([
|
|
151
|
+
_trace_named_project("old", "rare-project", offset_min=0),
|
|
152
|
+
*[_trace_named_project(f"t{i}", "common-project", offset_min=10 + i) for i in range(5)],
|
|
153
|
+
])
|
|
154
|
+
reader = TraceReader([exporter], max_traces=3)
|
|
155
|
+
names = {p["project_name"] for p in reader.get_projects()}
|
|
156
|
+
assert "rare-project" in names
|
|
@@ -8,9 +8,14 @@ PRICE_TABLE: Dict[str, Dict[str, float]] = {
|
|
|
8
8
|
"gpt-4-turbo": {"input": 0.01000, "output": 0.03000},
|
|
9
9
|
"gpt-4.1": {"input": 0.00200, "output": 0.00800, "cached": 0.000500},
|
|
10
10
|
"gpt-4.1-mini": {"input": 0.00040, "output": 0.00160, "cached": 0.000100},
|
|
11
|
+
"gpt-4.1-nano": {"input": 0.00010, "output": 0.00040, "cached": 0.000025},
|
|
11
12
|
"o3": {"input": 0.00200, "output": 0.00800, "cached": 0.000500},
|
|
12
13
|
"o4-mini": {"input": 0.00110, "output": 0.00440, "cached": 0.000275},
|
|
13
14
|
|
|
15
|
+
"text-embedding-3-small": {"input": 0.00002, "output": 0.0},
|
|
16
|
+
"text-embedding-3-large": {"input": 0.00013, "output": 0.0},
|
|
17
|
+
"text-embedding-ada-002": {"input": 0.00010, "output": 0.0},
|
|
18
|
+
|
|
14
19
|
"claude-opus-4-6": {"input": 0.00500, "output": 0.02500, "cached": 0.000500},
|
|
15
20
|
"claude-sonnet-4-6": {"input": 0.00300, "output": 0.01500, "cached": 0.000300},
|
|
16
21
|
"claude-haiku-4-5": {"input": 0.00100, "output": 0.00500, "cached": 0.000100},
|
|
@@ -62,3 +67,24 @@ def calculate_cost(
|
|
|
62
67
|
def _prefix_match(model: str, prices: Dict) -> Optional[Dict]:
|
|
63
68
|
provider = model.split("/")[0] + "/*"
|
|
64
69
|
return prices.get(provider)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# Audio isn't token-billed: transcription is per-minute of input audio, TTS is
|
|
73
|
+
# per-character of input text. gpt-4o-mini-tts's rate is an approximation
|
|
74
|
+
# (not published on OpenAI's current pricing page as of 2026-07) — verify
|
|
75
|
+
# against an actual invoice before trusting it for reconciliation.
|
|
76
|
+
AUDIO_PRICE_TABLE: Dict[str, Dict[str, float]] = {
|
|
77
|
+
"whisper-1": {"unit": "minute", "price": 0.006},
|
|
78
|
+
"gpt-4o-mini-tts": {"unit": "char", "price": 0.000015},
|
|
79
|
+
"tts-1": {"unit": "char", "price": 0.000015},
|
|
80
|
+
"tts-1-hd": {"unit": "char", "price": 0.00003},
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def calculate_audio_cost(model: str, *, minutes: float = 0.0, chars: int = 0) -> float:
|
|
85
|
+
entry = AUDIO_PRICE_TABLE.get(model)
|
|
86
|
+
if not entry:
|
|
87
|
+
return 0.0
|
|
88
|
+
if entry["unit"] == "minute":
|
|
89
|
+
return minutes * entry["price"]
|
|
90
|
+
return chars * entry["price"]
|
|
@@ -71,6 +71,22 @@ class TraceReader:
|
|
|
71
71
|
)
|
|
72
72
|
return [_hydrate_trace(r) for r in rows], total
|
|
73
73
|
|
|
74
|
+
def get_traces_for_metrics(
|
|
75
|
+
self,
|
|
76
|
+
project_name: Optional[str] = None,
|
|
77
|
+
project_id: Optional[str] = None,
|
|
78
|
+
) -> List[Trace]:
|
|
79
|
+
"""Like get_traces() but bypasses max_traces for queryable exporters,
|
|
80
|
+
so dashboard aggregates reflect the full dataset instead of a capped window."""
|
|
81
|
+
exporter = self._readable()
|
|
82
|
+
if exporter is None:
|
|
83
|
+
return self.get_traces()
|
|
84
|
+
total = exporter.count(project_name=project_name, project_id=project_id)
|
|
85
|
+
if total <= 0:
|
|
86
|
+
return []
|
|
87
|
+
rows = exporter.query(project_name=project_name, project_id=project_id, limit=total, offset=0)
|
|
88
|
+
return [_hydrate_trace(r) for r in rows]
|
|
89
|
+
|
|
74
90
|
def get_trace(self, trace_id: str) -> Optional[Trace]:
|
|
75
91
|
exporter = self._readable()
|
|
76
92
|
if exporter is not None and callable(getattr(exporter, "get", None)):
|
|
@@ -89,30 +105,30 @@ class TraceReader:
|
|
|
89
105
|
) -> list:
|
|
90
106
|
from .aggregator import compute_sessions
|
|
91
107
|
return compute_sessions(
|
|
92
|
-
self.
|
|
108
|
+
self.get_traces_for_metrics(),
|
|
93
109
|
project_name=project_name,
|
|
94
110
|
project_id=project_id,
|
|
95
111
|
user_id=user_id,
|
|
96
112
|
)
|
|
97
113
|
|
|
98
114
|
def get_session(self, session_id: str) -> List[Trace]:
|
|
99
|
-
return [t for t in self.
|
|
115
|
+
return [t for t in self.get_traces_for_metrics() if t.session_id == session_id]
|
|
100
116
|
|
|
101
117
|
def get_projects(self) -> list:
|
|
102
118
|
from .aggregator import compute_projects
|
|
103
|
-
return compute_projects(self.
|
|
119
|
+
return compute_projects(self.get_traces_for_metrics())
|
|
104
120
|
|
|
105
121
|
def get_subprojects(self, project_name: str) -> list:
|
|
106
122
|
from .aggregator import compute_projects_by_id
|
|
107
|
-
traces = [t for t in self.
|
|
123
|
+
traces = [t for t in self.get_traces_for_metrics() if t.project_name == project_name]
|
|
108
124
|
return compute_projects_by_id(traces)
|
|
109
125
|
|
|
110
126
|
def get_project(self, project_id: str) -> List[Trace]:
|
|
111
|
-
return [t for t in self.
|
|
127
|
+
return [t for t in self.get_traces_for_metrics() if t.project_id == project_id]
|
|
112
128
|
|
|
113
129
|
def get_filter_options(self) -> dict:
|
|
114
130
|
from .aggregator import compute_filter_options
|
|
115
|
-
return compute_filter_options(self.
|
|
131
|
+
return compute_filter_options(self.get_traces_for_metrics())
|
|
116
132
|
|
|
117
133
|
def _read_from(self, exporter) -> List[Trace]:
|
|
118
134
|
name = type(exporter).__name__
|
|
@@ -122,7 +122,7 @@ def _make_router(reader: TraceReader, prefix: str = "") -> "APIRouter":
|
|
|
122
122
|
project_name: Optional[str] = Query(None),
|
|
123
123
|
project_id: Optional[str] = Query(None),
|
|
124
124
|
):
|
|
125
|
-
traces = reader.
|
|
125
|
+
traces = reader.get_traces_for_metrics(project_name=project_name, project_id=project_id)
|
|
126
126
|
from_parsed = _parse_iso(from_dt)
|
|
127
127
|
to_parsed = _parse_iso(to_dt)
|
|
128
128
|
return compute_metrics(
|