agentops-accelerator 0.3.0__py3-none-any.whl
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.
- agentops/__init__.py +10 -0
- agentops/__main__.py +6 -0
- agentops/agent/__init__.py +12 -0
- agentops/agent/_legacy_ids.py +92 -0
- agentops/agent/analyzer.py +207 -0
- agentops/agent/checks/__init__.py +1 -0
- agentops/agent/checks/catalog.py +880 -0
- agentops/agent/checks/errors.py +279 -0
- agentops/agent/checks/foundry_config.py +75 -0
- agentops/agent/checks/latency.py +84 -0
- agentops/agent/checks/opex.py +157 -0
- agentops/agent/checks/opex_workspace.py +874 -0
- agentops/agent/checks/posture.py +36 -0
- agentops/agent/checks/posture_rules/__init__.py +53 -0
- agentops/agent/checks/posture_rules/content_filter.py +59 -0
- agentops/agent/checks/posture_rules/diagnostics.py +74 -0
- agentops/agent/checks/posture_rules/local_auth.py +55 -0
- agentops/agent/checks/posture_rules/managed_identity.py +59 -0
- agentops/agent/checks/posture_rules/network.py +68 -0
- agentops/agent/checks/regression.py +78 -0
- agentops/agent/checks/release_readiness.py +182 -0
- agentops/agent/checks/safety.py +247 -0
- agentops/agent/checks/spec_conformance.py +375 -0
- agentops/agent/cockpit.py +5159 -0
- agentops/agent/config.py +240 -0
- agentops/agent/findings.py +113 -0
- agentops/agent/history.py +142 -0
- agentops/agent/knowledge/__init__.py +182 -0
- agentops/agent/knowledge/waf-checklist.csv +39 -0
- agentops/agent/llm_assist/__init__.py +16 -0
- agentops/agent/llm_assist/_base.py +124 -0
- agentops/agent/llm_assist/_bundle_rule.py +154 -0
- agentops/agent/llm_assist/_client.py +347 -0
- agentops/agent/llm_assist/_dataset_rules.py +191 -0
- agentops/agent/llm_assist/_engine.py +106 -0
- agentops/agent/llm_assist/_prompt_rules.py +291 -0
- agentops/agent/llm_assist/_spec_rules.py +235 -0
- agentops/agent/production_telemetry.py +430 -0
- agentops/agent/report.py +207 -0
- agentops/agent/server/__init__.py +1 -0
- agentops/agent/server/app.py +84 -0
- agentops/agent/server/auth.py +94 -0
- agentops/agent/server/chat.py +44 -0
- agentops/agent/server/protocol.py +72 -0
- agentops/agent/sources/__init__.py +1 -0
- agentops/agent/sources/azure_monitor.py +523 -0
- agentops/agent/sources/azure_resources.py +602 -0
- agentops/agent/sources/foundry_control.py +174 -0
- agentops/agent/sources/results_history.py +494 -0
- agentops/agent/sources/spec_detectors/__init__.py +42 -0
- agentops/agent/sources/spec_detectors/_base.py +58 -0
- agentops/agent/sources/spec_detectors/agents_md.py +75 -0
- agentops/agent/sources/spec_detectors/spec_kit.py +172 -0
- agentops/agent/time_range.py +117 -0
- agentops/cli/__init__.py +1 -0
- agentops/cli/app.py +4823 -0
- agentops/core/__init__.py +1 -0
- agentops/core/agentops_config.py +592 -0
- agentops/core/config_loader.py +22 -0
- agentops/core/evaluators.py +480 -0
- agentops/core/release_evidence.py +56 -0
- agentops/core/results.py +117 -0
- agentops/mcp/__init__.py +10 -0
- agentops/mcp/server.py +232 -0
- agentops/pipeline/__init__.py +8 -0
- agentops/pipeline/cloud_results.py +189 -0
- agentops/pipeline/cloud_runner.py +901 -0
- agentops/pipeline/comparison.py +108 -0
- agentops/pipeline/diagnostics.py +51 -0
- agentops/pipeline/invocations.py +535 -0
- agentops/pipeline/official_eval.py +414 -0
- agentops/pipeline/orchestrator.py +775 -0
- agentops/pipeline/prompt_deploy.py +377 -0
- agentops/pipeline/publisher.py +121 -0
- agentops/pipeline/reporter.py +202 -0
- agentops/pipeline/runtime.py +409 -0
- agentops/pipeline/thresholds.py +84 -0
- agentops/services/__init__.py +1 -0
- agentops/services/cicd.py +720 -0
- agentops/services/eval_analysis.py +848 -0
- agentops/services/evidence_pack.py +757 -0
- agentops/services/initializer.py +86 -0
- agentops/services/preflight.py +470 -0
- agentops/services/setup_wizard.py +709 -0
- agentops/services/skills.py +643 -0
- agentops/services/trace_promotion.py +300 -0
- agentops/services/workflow_analysis.py +1129 -0
- agentops/templates/.gitignore +15 -0
- agentops/templates/__init__.py +1 -0
- agentops/templates/agent-server/Dockerfile +23 -0
- agentops/templates/agent-server/README.md +61 -0
- agentops/templates/agent-server/main.bicep +94 -0
- agentops/templates/agent.yaml +87 -0
- agentops/templates/agentops.yaml +58 -0
- agentops/templates/foundry.svg +71 -0
- agentops/templates/icon.png +0 -0
- agentops/templates/pipelines/azuredevops/agentops-deploy-dev-azd.yml +118 -0
- agentops/templates/pipelines/azuredevops/agentops-deploy-dev.yml +73 -0
- agentops/templates/pipelines/azuredevops/agentops-deploy-prod-azd.yml +141 -0
- agentops/templates/pipelines/azuredevops/agentops-deploy-prod.yml +94 -0
- agentops/templates/pipelines/azuredevops/agentops-deploy-prompt-agent.yml +167 -0
- agentops/templates/pipelines/azuredevops/agentops-deploy-qa-azd.yml +118 -0
- agentops/templates/pipelines/azuredevops/agentops-deploy-qa.yml +68 -0
- agentops/templates/pipelines/azuredevops/agentops-pr-prompt-agent.yml +210 -0
- agentops/templates/pipelines/azuredevops/agentops-pr.yml +155 -0
- agentops/templates/pipelines/azuredevops/agentops-watchdog.yml +106 -0
- agentops/templates/project.gitignore +36 -0
- agentops/templates/sample-traces.jsonl +3 -0
- agentops/templates/skills/agentops-agent/SKILL.md +137 -0
- agentops/templates/skills/agentops-config/SKILL.md +113 -0
- agentops/templates/skills/agentops-dataset/SKILL.md +84 -0
- agentops/templates/skills/agentops-eval/SKILL.md +189 -0
- agentops/templates/skills/agentops-report/SKILL.md +71 -0
- agentops/templates/skills/agentops-workflow/SKILL.md +471 -0
- agentops/templates/smoke.jsonl +3 -0
- agentops/templates/waf-checklist.README.md +84 -0
- agentops/templates/waf-checklist.csv +22 -0
- agentops/templates/workflows/agentops-deploy-dev-azd.yml +166 -0
- agentops/templates/workflows/agentops-deploy-dev.yml +187 -0
- agentops/templates/workflows/agentops-deploy-prod-azd.yml +183 -0
- agentops/templates/workflows/agentops-deploy-prod.yml +171 -0
- agentops/templates/workflows/agentops-deploy-prompt-agent.yml +197 -0
- agentops/templates/workflows/agentops-deploy-qa-azd.yml +156 -0
- agentops/templates/workflows/agentops-deploy-qa.yml +145 -0
- agentops/templates/workflows/agentops-pr-prompt-agent.yml +210 -0
- agentops/templates/workflows/agentops-pr.yml +148 -0
- agentops/templates/workflows/agentops-watchdog.yml +122 -0
- agentops/utils/__init__.py +1 -0
- agentops/utils/azd_env.py +435 -0
- agentops/utils/azure_endpoints.py +62 -0
- agentops/utils/colors.py +47 -0
- agentops/utils/dotenv_loader.py +105 -0
- agentops/utils/foundry_discovery.py +229 -0
- agentops/utils/logging.py +59 -0
- agentops/utils/telemetry.py +554 -0
- agentops/utils/yaml.py +36 -0
- agentops_accelerator-0.3.0.dist-info/METADATA +278 -0
- agentops_accelerator-0.3.0.dist-info/RECORD +142 -0
- agentops_accelerator-0.3.0.dist-info/WHEEL +5 -0
- agentops_accelerator-0.3.0.dist-info/entry_points.txt +2 -0
- agentops_accelerator-0.3.0.dist-info/licenses/LICENSE +21 -0
- agentops_accelerator-0.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"""Discover Foundry-attached resources from a project endpoint.
|
|
2
|
+
|
|
3
|
+
Currently exposes one helper: :func:`resolve_appinsights_connection`,
|
|
4
|
+
which asks a Foundry project for the connection string of the
|
|
5
|
+
Application Insights resource attached to it. Used by
|
|
6
|
+
:func:`agentops.utils.telemetry.init_tracing` as a fallback when the
|
|
7
|
+
user has configured ``AZURE_AI_FOUNDRY_PROJECT_ENDPOINT`` but not the
|
|
8
|
+
explicit ``APPLICATIONINSIGHTS_CONNECTION_STRING`` env var.
|
|
9
|
+
|
|
10
|
+
All Azure SDK imports are lazy; the discovery is best-effort and never
|
|
11
|
+
raises into callers - a missing SDK, a 404, or any unexpected response
|
|
12
|
+
shape returns ``None`` and the caller falls back to its no-op path.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import logging
|
|
18
|
+
import os
|
|
19
|
+
import threading
|
|
20
|
+
import time
|
|
21
|
+
from typing import Optional, Tuple
|
|
22
|
+
|
|
23
|
+
log = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Per-process cache so the cockpit does not re-query Foundry on every
|
|
27
|
+
# page load. Successful results are remembered for a long window
|
|
28
|
+
# (discovery rarely changes); failures are remembered for a short
|
|
29
|
+
# window so transient blips do not pin the cockpit into the error
|
|
30
|
+
# state across many reloads.
|
|
31
|
+
_SUCCESS_TTL_SECONDS = 30 * 60
|
|
32
|
+
_FAILURE_TTL_SECONDS = 60
|
|
33
|
+
_cache_lock = threading.Lock()
|
|
34
|
+
_cache: dict[str, Tuple[float, Optional[str], Optional[str]]] = {}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _store(key: str, conn: Optional[str], reason: Optional[str]) -> None:
|
|
38
|
+
with _cache_lock:
|
|
39
|
+
_cache[key] = (time.time(), conn, reason)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _lookup(key: str) -> Optional[Tuple[Optional[str], Optional[str]]]:
|
|
43
|
+
with _cache_lock:
|
|
44
|
+
entry = _cache.get(key)
|
|
45
|
+
if entry is None:
|
|
46
|
+
return None
|
|
47
|
+
ts, conn, reason = entry
|
|
48
|
+
ttl = _SUCCESS_TTL_SECONDS if conn else _FAILURE_TTL_SECONDS
|
|
49
|
+
if time.time() - ts > ttl:
|
|
50
|
+
return None
|
|
51
|
+
return conn, reason
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def reset_cache() -> None:
|
|
55
|
+
"""Clear the per-process discovery cache (test helper)."""
|
|
56
|
+
with _cache_lock:
|
|
57
|
+
_cache.clear()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _summarize_discovery_exception(exc: Exception, *, context: str) -> str:
|
|
61
|
+
text = str(exc)
|
|
62
|
+
lower = text.lower()
|
|
63
|
+
auth_markers = (
|
|
64
|
+
"defaultazurecredential failed to retrieve a token",
|
|
65
|
+
"azureclicredential: failed to invoke the azure cli",
|
|
66
|
+
"azurepowershellcredential: failed to invoke powershell",
|
|
67
|
+
"environmentcredential authentication unavailable",
|
|
68
|
+
"sharedtokencachecredential authentication unavailable",
|
|
69
|
+
"clientauthenticationerror",
|
|
70
|
+
)
|
|
71
|
+
if type(exc).__name__ == "ClientAuthenticationError" or any(
|
|
72
|
+
marker in lower for marker in auth_markers
|
|
73
|
+
):
|
|
74
|
+
return (
|
|
75
|
+
"Foundry authentication failed while reading telemetry metadata. "
|
|
76
|
+
"Run `az login` in this shell, confirm the active account has "
|
|
77
|
+
"Reader on the Foundry project resource group, then re-run."
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
permission_markers = (
|
|
81
|
+
"authorizationfailed",
|
|
82
|
+
"forbidden",
|
|
83
|
+
"does not have authorization",
|
|
84
|
+
"insufficient privileges",
|
|
85
|
+
)
|
|
86
|
+
if any(marker in lower for marker in permission_markers):
|
|
87
|
+
return (
|
|
88
|
+
"Foundry telemetry metadata is not readable by the signed-in "
|
|
89
|
+
"identity. Grant Reader on the Foundry project resource group "
|
|
90
|
+
"or set APPLICATIONINSIGHTS_CONNECTION_STRING manually."
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
snippet = text.splitlines()[0].strip() if text else type(exc).__name__
|
|
94
|
+
if len(snippet) > 220:
|
|
95
|
+
snippet = snippet[:217] + "..."
|
|
96
|
+
return f"{context} failed ({type(exc).__name__}: {snippet})."
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def resolve_appinsights_connection_with_reason(
|
|
100
|
+
project_endpoint: str,
|
|
101
|
+
) -> Tuple[Optional[str], Optional[str]]:
|
|
102
|
+
"""Return ``(connection_string, error_reason)`` for *project_endpoint*.
|
|
103
|
+
|
|
104
|
+
On success, ``connection_string`` is the App Insights connection
|
|
105
|
+
string and ``error_reason`` is ``None``. On failure, the
|
|
106
|
+
connection string is ``None`` and ``error_reason`` is a short,
|
|
107
|
+
user-actionable explanation suitable for surfacing in the
|
|
108
|
+
cockpit tile.
|
|
109
|
+
|
|
110
|
+
Successful results are cached in-process for 30 minutes; failure
|
|
111
|
+
results for 60 seconds (so a transient Foundry hiccup does not
|
|
112
|
+
pin the cockpit into the error state for half an hour).
|
|
113
|
+
"""
|
|
114
|
+
if not project_endpoint:
|
|
115
|
+
return None, "no AZURE_AI_FOUNDRY_PROJECT_ENDPOINT set"
|
|
116
|
+
|
|
117
|
+
cached = _lookup(project_endpoint)
|
|
118
|
+
if cached is not None:
|
|
119
|
+
return cached
|
|
120
|
+
|
|
121
|
+
try:
|
|
122
|
+
from azure.ai.projects import AIProjectClient
|
|
123
|
+
from azure.identity import DefaultAzureCredential
|
|
124
|
+
except ImportError:
|
|
125
|
+
reason = (
|
|
126
|
+
"azure-ai-projects / azure-identity not installed in the "
|
|
127
|
+
"cockpit's Python environment. Install with "
|
|
128
|
+
"`pip install azure-ai-projects azure-identity`."
|
|
129
|
+
)
|
|
130
|
+
log.debug(reason)
|
|
131
|
+
_store(project_endpoint, None, reason)
|
|
132
|
+
return None, reason
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
credential = DefaultAzureCredential(exclude_developer_cli_credential=True, process_timeout=30)
|
|
136
|
+
client = AIProjectClient(
|
|
137
|
+
endpoint=project_endpoint,
|
|
138
|
+
credential=credential,
|
|
139
|
+
)
|
|
140
|
+
except Exception as exc: # noqa: BLE001
|
|
141
|
+
reason = _summarize_discovery_exception(
|
|
142
|
+
exc,
|
|
143
|
+
context="Could not build AIProjectClient",
|
|
144
|
+
)
|
|
145
|
+
log.debug(reason)
|
|
146
|
+
_store(project_endpoint, None, reason)
|
|
147
|
+
return None, reason
|
|
148
|
+
|
|
149
|
+
telemetry_attr = getattr(client, "telemetry", None)
|
|
150
|
+
if telemetry_attr is None:
|
|
151
|
+
reason = (
|
|
152
|
+
"AIProjectClient has no .telemetry helper "
|
|
153
|
+
"(azure-ai-projects too old). Set "
|
|
154
|
+
"APPLICATIONINSIGHTS_CONNECTION_STRING manually."
|
|
155
|
+
)
|
|
156
|
+
log.debug(reason)
|
|
157
|
+
_store(project_endpoint, None, reason)
|
|
158
|
+
return None, reason
|
|
159
|
+
|
|
160
|
+
# The exact method name has shifted slightly across SDK versions;
|
|
161
|
+
# try the documented one first, then a couple of known aliases.
|
|
162
|
+
candidate_methods = (
|
|
163
|
+
"get_application_insights_connection_string",
|
|
164
|
+
"get_connection_string",
|
|
165
|
+
"connection_string",
|
|
166
|
+
)
|
|
167
|
+
last_exc: Optional[Exception] = None
|
|
168
|
+
for name in candidate_methods:
|
|
169
|
+
fn = getattr(telemetry_attr, name, None)
|
|
170
|
+
if fn is None:
|
|
171
|
+
continue
|
|
172
|
+
try:
|
|
173
|
+
value = fn() if callable(fn) else fn
|
|
174
|
+
except Exception as exc: # noqa: BLE001
|
|
175
|
+
last_exc = exc
|
|
176
|
+
log.debug(
|
|
177
|
+
"AIProjectClient.telemetry.%s raised %s; trying next.",
|
|
178
|
+
name,
|
|
179
|
+
exc,
|
|
180
|
+
)
|
|
181
|
+
continue
|
|
182
|
+
if isinstance(value, str) and value:
|
|
183
|
+
_store(project_endpoint, value, None)
|
|
184
|
+
return value, None
|
|
185
|
+
|
|
186
|
+
if last_exc is not None:
|
|
187
|
+
reason = _summarize_discovery_exception(
|
|
188
|
+
last_exc,
|
|
189
|
+
context="Foundry telemetry discovery",
|
|
190
|
+
)
|
|
191
|
+
else:
|
|
192
|
+
reason = (
|
|
193
|
+
"Foundry returned no Application Insights connection. Wire "
|
|
194
|
+
"one in: Project details \u2192 Connected resources \u2192 "
|
|
195
|
+
"Add connection \u2192 Application Insights."
|
|
196
|
+
)
|
|
197
|
+
log.debug(reason)
|
|
198
|
+
_store(project_endpoint, None, reason)
|
|
199
|
+
return None, reason
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def resolve_appinsights_connection(project_endpoint: str) -> Optional[str]:
|
|
203
|
+
"""Return the App Insights connection string for *project_endpoint*.
|
|
204
|
+
|
|
205
|
+
Returns ``None`` on any failure. See
|
|
206
|
+
:func:`resolve_appinsights_connection_with_reason` for the
|
|
207
|
+
diagnostic-aware variant used by the cockpit.
|
|
208
|
+
"""
|
|
209
|
+
conn, _ = resolve_appinsights_connection_with_reason(project_endpoint)
|
|
210
|
+
return conn
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def resolve_appinsights_connection_from_env() -> Optional[str]:
|
|
214
|
+
"""Resolve using ``AZURE_AI_FOUNDRY_PROJECT_ENDPOINT`` if set."""
|
|
215
|
+
endpoint = os.getenv("AZURE_AI_FOUNDRY_PROJECT_ENDPOINT")
|
|
216
|
+
if not endpoint:
|
|
217
|
+
return None
|
|
218
|
+
return resolve_appinsights_connection(endpoint)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def resolve_appinsights_connection_from_env_with_reason() -> Tuple[
|
|
222
|
+
Optional[str], Optional[str]
|
|
223
|
+
]:
|
|
224
|
+
"""Variant of :func:`resolve_appinsights_connection_from_env` that
|
|
225
|
+
also returns the error reason when discovery fails."""
|
|
226
|
+
endpoint = os.getenv("AZURE_AI_FOUNDRY_PROJECT_ENDPOINT")
|
|
227
|
+
if not endpoint:
|
|
228
|
+
return None, "no AZURE_AI_FOUNDRY_PROJECT_ENDPOINT set"
|
|
229
|
+
return resolve_appinsights_connection_with_reason(endpoint)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Logging configuration for AgentOps CLI.
|
|
2
|
+
|
|
3
|
+
No side effects at import time - call setup_logging() explicitly from the
|
|
4
|
+
CLI callback before any command runs.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
|
|
11
|
+
_LOG_FORMAT = "%(levelname)s: %(message)s"
|
|
12
|
+
_LOG_FORMAT_VERBOSE = "%(asctime)s %(name)s %(levelname)s: %(message)s"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def setup_logging(verbose: bool = False) -> None:
|
|
16
|
+
"""Configure root logger.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
verbose: When True, set level to DEBUG and include timestamps.
|
|
20
|
+
When False (default), set level to INFO.
|
|
21
|
+
"""
|
|
22
|
+
level = logging.DEBUG if verbose else logging.INFO
|
|
23
|
+
fmt = _LOG_FORMAT_VERBOSE if verbose else _LOG_FORMAT
|
|
24
|
+
|
|
25
|
+
logging.basicConfig(
|
|
26
|
+
level=level,
|
|
27
|
+
format=fmt,
|
|
28
|
+
force=True, # safe to call multiple times (e.g. in tests)
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Silence noisy third-party loggers unless we are in DEBUG mode
|
|
32
|
+
if not verbose:
|
|
33
|
+
logging.getLogger("urllib3").setLevel(logging.WARNING)
|
|
34
|
+
logging.getLogger("azure").setLevel(logging.WARNING)
|
|
35
|
+
# azure.identity emits WARNING when individual credential sources
|
|
36
|
+
# in DefaultAzureCredential fail (e.g. the Azure CLI is locked or
|
|
37
|
+
# times out). Those failures are usually transient and the chain
|
|
38
|
+
# still succeeds via another source, so we hide them at the user
|
|
39
|
+
# level. They are still surfaced if the run fails outright.
|
|
40
|
+
logging.getLogger("azure.identity").setLevel(logging.ERROR)
|
|
41
|
+
logging.getLogger("azure.core").setLevel(logging.WARNING)
|
|
42
|
+
logging.getLogger("azure.core.pipeline").setLevel(logging.WARNING)
|
|
43
|
+
logging.getLogger("azure.core.pipeline.policies.http_logging_policy").setLevel(
|
|
44
|
+
logging.WARNING
|
|
45
|
+
)
|
|
46
|
+
logging.getLogger("azure.ai.evaluation").setLevel(logging.CRITICAL)
|
|
47
|
+
logging.getLogger("azure.ai.evaluation._legacy").setLevel(logging.CRITICAL)
|
|
48
|
+
logging.getLogger("httpx").setLevel(logging.WARNING)
|
|
49
|
+
logging.getLogger("openai").setLevel(logging.WARNING)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_logger(name: str) -> logging.Logger:
|
|
53
|
+
"""Return a module-level logger.
|
|
54
|
+
|
|
55
|
+
Usage:
|
|
56
|
+
log = get_logger(__name__)
|
|
57
|
+
log.debug("...")
|
|
58
|
+
"""
|
|
59
|
+
return logging.getLogger(name)
|