x-ipe 1.0.23__py3-none-any.whl → 1.0.25__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.
- x_ipe/app.py +32 -1
- x_ipe/handlers/terminal_handlers.py +6 -0
- x_ipe/handlers/voice_handlers.py +5 -0
- x_ipe/resources/copilot-instructions.md +19 -6
- x_ipe/resources/skills/lesson-learned/SKILL.md +208 -0
- x_ipe/resources/skills/lesson-learned/references/examples.md +238 -0
- x_ipe/resources/skills/project-quality-board-management/SKILL.md +135 -298
- x_ipe/resources/skills/project-quality-board-management/references/evaluation-principles.md +213 -0
- x_ipe/resources/skills/project-quality-board-management/references/evaluation-procedures.md +214 -0
- x_ipe/resources/skills/project-quality-board-management/templates/quality-report.md +70 -18
- x_ipe/resources/skills/task-execution-guideline/SKILL.md +2 -2
- x_ipe/resources/skills/task-execution-guideline/templates/task-record.yaml +1 -1
- x_ipe/resources/skills/task-type-code-implementation/SKILL.md +72 -270
- x_ipe/resources/skills/task-type-code-implementation/references/implementation-guidelines.md +432 -0
- x_ipe/resources/skills/task-type-code-refactor-v2/SKILL.md +127 -353
- x_ipe/resources/skills/task-type-code-refactor-v2/references/refactoring-techniques.md +373 -0
- x_ipe/resources/skills/task-type-feature-breakdown/SKILL.md +31 -243
- x_ipe/resources/skills/task-type-feature-breakdown/references/breakdown-guidelines.md +330 -0
- x_ipe/resources/skills/task-type-feature-refinement/SKILL.md +27 -180
- x_ipe/resources/skills/task-type-feature-refinement/references/specification-writing-guide.md +267 -0
- x_ipe/resources/skills/task-type-idea-mockup/SKILL.md +38 -276
- x_ipe/resources/skills/task-type-idea-mockup/references/mockup-guidelines.md +299 -0
- x_ipe/resources/skills/task-type-idea-to-architecture/SKILL.md +20 -218
- x_ipe/resources/skills/task-type-idea-to-architecture/references/architecture-patterns.md +342 -0
- x_ipe/resources/skills/task-type-ideation/SKILL.md +10 -266
- x_ipe/resources/skills/task-type-ideation/references/folder-naming-guide.md +55 -0
- x_ipe/resources/skills/task-type-ideation/references/tool-usage-guide.md +236 -0
- x_ipe/resources/skills/task-type-ideation-v2/SKILL.md +488 -0
- x_ipe/resources/skills/task-type-ideation-v2/references/examples.md +377 -0
- x_ipe/resources/skills/task-type-ideation-v2/references/folder-naming-guide.md +74 -0
- x_ipe/resources/skills/task-type-ideation-v2/references/tool-usage-guide.md +145 -0
- x_ipe/resources/skills/task-type-ideation-v2/references/visualization-guide.md +160 -0
- x_ipe/resources/skills/task-type-ideation-v2/templates/idea-summary.md +86 -0
- x_ipe/resources/skills/task-type-refactoring-analysis/SKILL.md +83 -145
- x_ipe/resources/skills/task-type-refactoring-analysis/references/output-schema.md +172 -0
- x_ipe/resources/skills/task-type-technical-design/SKILL.md +28 -214
- x_ipe/resources/skills/task-type-technical-design/references/design-templates.md +422 -0
- x_ipe/resources/skills/task-type-test-generation/SKILL.md +47 -332
- x_ipe/resources/skills/task-type-test-generation/references/test-patterns.md +368 -0
- x_ipe/resources/skills/tool-tracing-creator/SKILL.md +312 -0
- x_ipe/resources/skills/tool-tracing-creator/references/examples.md +324 -0
- x_ipe/resources/skills/tool-tracing-instrumentation/SKILL.md +373 -0
- x_ipe/resources/skills/tool-tracing-instrumentation/references/examples.md +264 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/SKILL.md +486 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/10. example-gate-conditions.md +73 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/11. reference-quality-standards.md +127 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/2. reference-section-order.md +127 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/3. example-step-based-code-review.md +84 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/4. example-step-based-feature-implementation.md +113 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/5. example-function-based-validation.md +73 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/6. example-function-based-analysis.md +94 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/7. example-task-io-code-implementation.md +36 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/8. example-structured-summary.md +43 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/9. example-dor-dod.md +77 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/examples.md +429 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/skill-general-guidelines-v2.md +611 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-meta.md +153 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-task-based.md +324 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-task-category.md +109 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-tool.md +205 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-meta.md +334 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-task-based.md +279 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-tool.md +175 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-workflow-orchestration.md +329 -0
- x_ipe/resources/skills/x-ipe-task-based-ideation/SKILL.md +487 -0
- x_ipe/resources/skills/x-ipe-task-based-ideation/references/examples.md +377 -0
- x_ipe/resources/skills/x-ipe-task-based-ideation/references/folder-naming-guide.md +74 -0
- x_ipe/resources/skills/x-ipe-task-based-ideation/references/tool-usage-guide.md +145 -0
- x_ipe/resources/skills/x-ipe-task-based-ideation/references/visualization-guide.md +160 -0
- x_ipe/resources/skills/x-ipe-task-based-ideation/templates/idea-summary.md +86 -0
- x_ipe/routes/__init__.py +2 -0
- x_ipe/routes/ideas_routes.py +289 -0
- x_ipe/routes/kb_routes.py +80 -0
- x_ipe/routes/main_routes.py +18 -0
- x_ipe/routes/project_routes.py +7 -0
- x_ipe/routes/proxy_routes.py +10 -2
- x_ipe/routes/quality_evaluation_routes.py +193 -0
- x_ipe/routes/settings_routes.py +6 -0
- x_ipe/routes/tools_routes.py +6 -0
- x_ipe/routes/tracing_routes.py +232 -0
- x_ipe/routes/uiux_feedback_routes.py +50 -0
- x_ipe/services/__init__.py +5 -0
- x_ipe/services/config_service.py +6 -0
- x_ipe/services/file_service.py +20 -0
- x_ipe/services/homepage_service.py +160 -0
- x_ipe/services/ideas_service.py +535 -2
- x_ipe/services/kb_service.py +378 -0
- x_ipe/services/proxy_service.py +37 -7
- x_ipe/services/settings_service.py +13 -0
- x_ipe/services/skills_service.py +4 -0
- x_ipe/services/terminal_service.py +24 -0
- x_ipe/services/themes_service.py +4 -0
- x_ipe/services/tools_config_service.py +4 -0
- x_ipe/services/tracing_service.py +333 -0
- x_ipe/services/uiux_feedback_service.py +148 -1
- x_ipe/services/voice_input_service_v2.py +11 -0
- x_ipe/static/css/base.css +7 -0
- x_ipe/static/css/homepage-infinity.css +330 -0
- x_ipe/static/css/kb-core.css +301 -0
- x_ipe/static/css/quality-evaluation.css +345 -0
- x_ipe/static/css/sidebar.css +14 -4
- x_ipe/static/css/terminal.css +23 -0
- x_ipe/static/css/tracing-dashboard.css +796 -0
- x_ipe/static/css/uiux-feedback.css +7 -1
- x_ipe/static/css/workplace.css +636 -0
- x_ipe/static/img/homepage-infinity-loop.png +0 -0
- x_ipe/static/js/features/confirm-dialog.js +169 -0
- x_ipe/static/js/features/folder-view.js +742 -0
- x_ipe/static/js/features/homepage-infinity.js +314 -0
- x_ipe/static/js/features/kb-core.js +371 -0
- x_ipe/static/js/features/quality-evaluation.js +387 -0
- x_ipe/static/js/features/sidebar.js +255 -12
- x_ipe/static/js/features/tracing-dashboard.js +855 -0
- x_ipe/static/js/features/tracing-graph.js +1031 -0
- x_ipe/static/js/features/tree-drag.js +227 -0
- x_ipe/static/js/features/tree-search.js +228 -0
- x_ipe/static/js/features/workplace.js +661 -33
- x_ipe/static/js/init.js +76 -0
- x_ipe/static/js/terminal-v2.js +45 -14
- x_ipe/static/js/terminal.js +50 -49
- x_ipe/static/js/uiux-feedback.js +75 -16
- x_ipe/templates/base.html +24 -0
- x_ipe/templates/index.html +10 -1
- x_ipe/templates/knowledge-base.html +110 -0
- x_ipe/templates/workplace.html +4 -0
- x_ipe/tracing/__init__.py +37 -0
- x_ipe/tracing/buffer.py +135 -0
- x_ipe/tracing/context.py +125 -0
- x_ipe/tracing/decorator.py +288 -0
- x_ipe/tracing/middleware.py +197 -0
- x_ipe/tracing/parser.py +235 -0
- x_ipe/tracing/redactor.py +111 -0
- x_ipe/tracing/writer.py +122 -0
- {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/METADATA +2 -2
- {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/RECORD +138 -65
- x_ipe/app.py.bak +0 -1333
- x_ipe/resources/skills/x-ipe-skill-creator/SKILL.md +0 -329
- x_ipe/resources/skills/x-ipe-skill-creator/references/output-patterns.md +0 -169
- x_ipe/resources/skills/x-ipe-skill-creator/references/skill-structure.md +0 -162
- x_ipe/resources/skills/x-ipe-skill-creator/references/workflows.md +0 -110
- x_ipe/resources/skills/x-ipe-skill-creator/templates/references/examples.md +0 -113
- x_ipe/resources/skills/x-ipe-skill-creator/templates/skill-category-skill.md +0 -296
- x_ipe/resources/skills/x-ipe-skill-creator/templates/task-type-skill.md +0 -269
- {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/WHEEL +0 -0
- {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/entry_points.txt +0 -0
- {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}Knowledge Base - X-IPE{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block body %}
|
|
6
|
+
<div class="app-container">
|
|
7
|
+
<!-- ROW 1: Top Bar -->
|
|
8
|
+
<header class="top-bar">
|
|
9
|
+
<div class="d-flex align-items-center gap-3">
|
|
10
|
+
<a href="/" class="top-bar-brand text-decoration-none">
|
|
11
|
+
<i class="bi bi-journal-code me-2"></i>X-IPE
|
|
12
|
+
</a>
|
|
13
|
+
<nav aria-label="breadcrumb" class="top-bar-breadcrumb">
|
|
14
|
+
<ol class="breadcrumb mb-0" id="breadcrumb">
|
|
15
|
+
<li class="breadcrumb-item active">Knowledge Base</li>
|
|
16
|
+
</ol>
|
|
17
|
+
</nav>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="d-flex align-items-center gap-2">
|
|
20
|
+
<button class="btn btn-sm btn-primary" id="btn-refresh-index" title="Refresh index">
|
|
21
|
+
<i class="bi bi-arrow-clockwise"></i> Refresh
|
|
22
|
+
</button>
|
|
23
|
+
<a href="/settings" class="btn btn-link text-light" title="Settings">
|
|
24
|
+
<i class="bi bi-gear-fill"></i>
|
|
25
|
+
</a>
|
|
26
|
+
</div>
|
|
27
|
+
</header>
|
|
28
|
+
|
|
29
|
+
<!-- ROW 2: Middle Section (sidebar + content) -->
|
|
30
|
+
<div class="middle-section" id="middle-section">
|
|
31
|
+
<!-- LEFT: Sidebar Navigation -->
|
|
32
|
+
<nav class="sidebar" id="sidebar">
|
|
33
|
+
<!-- Search Box -->
|
|
34
|
+
<div class="kb-sidebar-search p-2">
|
|
35
|
+
<input type="text" class="form-control form-control-sm" id="kb-search"
|
|
36
|
+
placeholder="Search files..." aria-label="Search knowledge base">
|
|
37
|
+
</div>
|
|
38
|
+
<!-- File Tree -->
|
|
39
|
+
<div class="sidebar-content" id="sidebar-content">
|
|
40
|
+
<div class="loading-spinner">
|
|
41
|
+
<div class="spinner-border spinner-border-sm text-light" role="status">
|
|
42
|
+
<span class="visually-hidden">Loading...</span>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</nav>
|
|
47
|
+
|
|
48
|
+
<!-- Resize Handle -->
|
|
49
|
+
<div class="sidebar-resize-handle" id="sidebar-resize-handle"></div>
|
|
50
|
+
|
|
51
|
+
<!-- RIGHT: Content Area -->
|
|
52
|
+
<main class="content-area">
|
|
53
|
+
<div class="content-view" id="content-view">
|
|
54
|
+
<div class="content-header d-flex justify-content-between align-items-center" id="content-header">
|
|
55
|
+
<h5 class="mb-0" id="content-title">Knowledge Base</h5>
|
|
56
|
+
<div class="kb-stats" id="kb-stats">
|
|
57
|
+
<!-- File count, topic count loaded here -->
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="content-body" id="content-body">
|
|
61
|
+
<!-- KB content loaded here -->
|
|
62
|
+
<div class="kb-landing-view" id="kb-landing-view">
|
|
63
|
+
<div class="kb-section">
|
|
64
|
+
<h6><i class="bi bi-inbox me-2"></i>Landing (Unprocessed)</h6>
|
|
65
|
+
<div class="kb-file-list" id="landing-files">
|
|
66
|
+
<p class="text-muted small">No files in landing folder</p>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="kb-section mt-4">
|
|
70
|
+
<h6><i class="bi bi-folder me-2"></i>Topics</h6>
|
|
71
|
+
<div class="kb-topics-grid" id="topics-grid">
|
|
72
|
+
<p class="text-muted small">No topics created yet</p>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</main>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<!-- ROW 3: Footer Terminal Panel -->
|
|
82
|
+
<div class="terminal-panel" id="terminal-panel">
|
|
83
|
+
<div class="terminal-header">
|
|
84
|
+
<div class="terminal-tabs" id="terminal-tabs">
|
|
85
|
+
<!-- Tabs rendered by JavaScript -->
|
|
86
|
+
</div>
|
|
87
|
+
<div class="d-flex align-items-center gap-2">
|
|
88
|
+
<button class="btn btn-sm btn-outline-light" id="btn-new-terminal" title="New Terminal">
|
|
89
|
+
<i class="bi bi-plus"></i>
|
|
90
|
+
</button>
|
|
91
|
+
<button class="btn btn-sm btn-outline-light terminal-toggle" id="terminal-toggle" title="Toggle Terminal">
|
|
92
|
+
<i class="bi bi-chevron-down"></i>
|
|
93
|
+
</button>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
<div class="terminal-body" id="terminal-body">
|
|
97
|
+
<!-- xterm.js terminals rendered here -->
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<script>
|
|
103
|
+
// Auto-initialize KB view when page loads
|
|
104
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
105
|
+
if (window.kbCore) {
|
|
106
|
+
window.kbCore.init();
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
</script>
|
|
110
|
+
{% endblock %}
|
x_ipe/templates/workplace.html
CHANGED
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
<button class="btn btn-sm btn-primary" id="btn-create-idea" title="Create new idea">
|
|
22
22
|
<i class="bi bi-plus-lg"></i> Create Idea
|
|
23
23
|
</button>
|
|
24
|
+
<!-- FEATURE-025-A: Knowledge Base Button -->
|
|
25
|
+
<button class="btn btn-sm btn-outline-secondary" id="btn-knowledge-base" title="Knowledge Base">
|
|
26
|
+
<i class="bi bi-archive"></i>
|
|
27
|
+
</button>
|
|
24
28
|
<!-- FEATURE-011: Stage Toolbox Button -->
|
|
25
29
|
<button class="btn btn-sm btn-outline-secondary" id="btn-stage-toolbox" title="Stage Toolbox">
|
|
26
30
|
<i class="bi bi-tools"></i>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FEATURE-023: Application Action Tracing - Core
|
|
3
|
+
|
|
4
|
+
Tracing module for X-IPE applications.
|
|
5
|
+
|
|
6
|
+
Provides automatic function tracing with sensitive data redaction,
|
|
7
|
+
execution timing, and structured log output.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
from x_ipe.tracing import x_ipe_tracing, TraceContext
|
|
11
|
+
|
|
12
|
+
@x_ipe_tracing(level="INFO", redact=["password"])
|
|
13
|
+
def my_function(email: str, password: str):
|
|
14
|
+
...
|
|
15
|
+
|
|
16
|
+
# Start/end traces manually (usually done by middleware)
|
|
17
|
+
TraceContext.start_trace("POST /api/endpoint")
|
|
18
|
+
# ... execute traced functions ...
|
|
19
|
+
buffer = TraceContext.end_trace()
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from .decorator import x_ipe_tracing
|
|
23
|
+
from .context import TraceContext
|
|
24
|
+
from .buffer import TraceBuffer, TraceEntry
|
|
25
|
+
from .writer import TraceLogWriter
|
|
26
|
+
from .redactor import Redactor
|
|
27
|
+
from .middleware import init_tracing_middleware
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
'x_ipe_tracing',
|
|
31
|
+
'TraceContext',
|
|
32
|
+
'TraceBuffer',
|
|
33
|
+
'TraceEntry',
|
|
34
|
+
'TraceLogWriter',
|
|
35
|
+
'Redactor',
|
|
36
|
+
'init_tracing_middleware',
|
|
37
|
+
]
|
x_ipe/tracing/buffer.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FEATURE-023: Application Action Tracing - Core
|
|
3
|
+
|
|
4
|
+
TraceBuffer and TraceEntry for in-memory trace storage.
|
|
5
|
+
|
|
6
|
+
Traces are collected in-memory during request execution and flushed
|
|
7
|
+
to log files upon request completion.
|
|
8
|
+
"""
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from datetime import datetime, timezone
|
|
11
|
+
from typing import List, Optional, Any
|
|
12
|
+
import json
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class TraceEntry:
|
|
17
|
+
"""
|
|
18
|
+
Single trace log entry representing a function call event.
|
|
19
|
+
|
|
20
|
+
Attributes:
|
|
21
|
+
timestamp: When the event occurred
|
|
22
|
+
trace_id: Unique identifier for the trace
|
|
23
|
+
level: Log level (INFO, DEBUG, ERROR)
|
|
24
|
+
direction: Arrow direction (→ for entry, ← for exit)
|
|
25
|
+
event_type: Type of event (start_function, return_function, exception)
|
|
26
|
+
function_name: Name of the traced function
|
|
27
|
+
data: Parameters, return value, or error details
|
|
28
|
+
duration_ms: Execution time in milliseconds (only for exit events)
|
|
29
|
+
depth: Nesting level (0 = root)
|
|
30
|
+
"""
|
|
31
|
+
timestamp: datetime
|
|
32
|
+
trace_id: str
|
|
33
|
+
level: str
|
|
34
|
+
direction: str
|
|
35
|
+
event_type: str
|
|
36
|
+
function_name: str
|
|
37
|
+
data: dict
|
|
38
|
+
duration_ms: Optional[float] = None
|
|
39
|
+
depth: int = 0
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class TraceBuffer:
|
|
43
|
+
"""
|
|
44
|
+
In-memory buffer for trace entries during request execution.
|
|
45
|
+
|
|
46
|
+
Collects trace entries and formats them for log file output.
|
|
47
|
+
Enforces a maximum size limit to prevent memory exhaustion.
|
|
48
|
+
|
|
49
|
+
Usage:
|
|
50
|
+
buffer = TraceBuffer("abc-123", "POST /api/orders")
|
|
51
|
+
buffer.add(TraceEntry(...))
|
|
52
|
+
log_content = buffer.to_log_string("SUCCESS", 150.0)
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
MAX_SIZE = 10 * 1024 * 1024 # 10MB limit
|
|
56
|
+
|
|
57
|
+
def __init__(self, trace_id: str, root_api: str):
|
|
58
|
+
"""
|
|
59
|
+
Initialize TraceBuffer.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
trace_id: Unique identifier for this trace
|
|
63
|
+
root_api: The root API call (e.g., "POST /api/orders")
|
|
64
|
+
"""
|
|
65
|
+
self.trace_id = trace_id
|
|
66
|
+
self.root_api = root_api
|
|
67
|
+
self.started_at = datetime.now(timezone.utc)
|
|
68
|
+
self.entries: List[TraceEntry] = []
|
|
69
|
+
self._size = 0
|
|
70
|
+
|
|
71
|
+
def add(self, entry: TraceEntry) -> None:
|
|
72
|
+
"""
|
|
73
|
+
Add a trace entry to the buffer.
|
|
74
|
+
|
|
75
|
+
Silently drops entries if buffer size limit is exceeded.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
entry: TraceEntry to add
|
|
79
|
+
"""
|
|
80
|
+
try:
|
|
81
|
+
entry_size = len(json.dumps(entry.data, default=str))
|
|
82
|
+
except (TypeError, ValueError):
|
|
83
|
+
entry_size = 100 # Fallback size estimate
|
|
84
|
+
|
|
85
|
+
if self._size + entry_size > self.MAX_SIZE:
|
|
86
|
+
return # Silently drop if buffer full
|
|
87
|
+
|
|
88
|
+
self.entries.append(entry)
|
|
89
|
+
self._size += entry_size
|
|
90
|
+
|
|
91
|
+
def to_log_string(self, status: str, total_ms: float) -> str:
|
|
92
|
+
"""
|
|
93
|
+
Format the buffer as a log file string.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
status: Final status (SUCCESS, ERROR)
|
|
97
|
+
total_ms: Total execution time in milliseconds
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Formatted log string ready for file output
|
|
101
|
+
"""
|
|
102
|
+
lines = [
|
|
103
|
+
f"[TRACE-START] {self.trace_id} | {self.root_api} | {self.started_at.isoformat()}Z"
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
for entry in self.entries:
|
|
107
|
+
indent = " " * (entry.depth + 1)
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
data_str = json.dumps(entry.data, default=str, ensure_ascii=False)
|
|
111
|
+
except (TypeError, ValueError):
|
|
112
|
+
data_str = str(entry.data)
|
|
113
|
+
|
|
114
|
+
# Truncate very long data
|
|
115
|
+
if len(data_str) > 1000:
|
|
116
|
+
data_str = data_str[:997] + "..."
|
|
117
|
+
|
|
118
|
+
if entry.duration_ms is not None:
|
|
119
|
+
line = (
|
|
120
|
+
f"{indent}[{entry.level}] {entry.direction} {entry.event_type}: "
|
|
121
|
+
f"{entry.function_name} | {data_str} | {entry.duration_ms:.0f}ms"
|
|
122
|
+
)
|
|
123
|
+
else:
|
|
124
|
+
line = (
|
|
125
|
+
f"{indent}[{entry.level}] {entry.direction} {entry.event_type}: "
|
|
126
|
+
f"{entry.function_name} | {data_str}"
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
lines.append(line)
|
|
130
|
+
|
|
131
|
+
lines.append(
|
|
132
|
+
f"[TRACE-END] {self.trace_id} | {total_ms:.0f}ms | {status}"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
return "\n".join(lines)
|
x_ipe/tracing/context.py
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FEATURE-023: Application Action Tracing - Core
|
|
3
|
+
|
|
4
|
+
TraceContext for thread-safe context propagation using contextvars.
|
|
5
|
+
|
|
6
|
+
Manages the active trace context across nested function calls,
|
|
7
|
+
ensuring trace ID propagation and proper nesting depth tracking.
|
|
8
|
+
"""
|
|
9
|
+
from contextvars import ContextVar
|
|
10
|
+
from typing import Optional, List
|
|
11
|
+
import uuid
|
|
12
|
+
|
|
13
|
+
from .buffer import TraceBuffer
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Thread-safe context variable for the active trace
|
|
17
|
+
_trace_context: ContextVar[Optional['TraceContext']] = ContextVar(
|
|
18
|
+
'trace_context',
|
|
19
|
+
default=None
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TraceContext:
|
|
24
|
+
"""
|
|
25
|
+
Thread-safe trace context manager.
|
|
26
|
+
|
|
27
|
+
Uses Python's contextvars to maintain trace state across async
|
|
28
|
+
function calls. Tracks trace ID, buffer, and call depth.
|
|
29
|
+
|
|
30
|
+
Usage:
|
|
31
|
+
# Start a new trace
|
|
32
|
+
ctx = TraceContext.start_trace("POST /api/orders")
|
|
33
|
+
|
|
34
|
+
# Get current context (in nested calls)
|
|
35
|
+
ctx = TraceContext.get_current()
|
|
36
|
+
|
|
37
|
+
# End trace and get buffer
|
|
38
|
+
buffer = TraceContext.end_trace()
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def __init__(self, trace_id: str, root_api: str):
|
|
42
|
+
"""
|
|
43
|
+
Initialize TraceContext.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
trace_id: Unique identifier for this trace
|
|
47
|
+
root_api: The root API call (e.g., "POST /api/orders")
|
|
48
|
+
"""
|
|
49
|
+
self.trace_id = trace_id
|
|
50
|
+
self.buffer = TraceBuffer(trace_id, root_api)
|
|
51
|
+
self.depth = 0
|
|
52
|
+
self._call_stack: List[str] = []
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def start_trace(cls, root_api: str) -> 'TraceContext':
|
|
56
|
+
"""
|
|
57
|
+
Start a new trace.
|
|
58
|
+
|
|
59
|
+
Generates a unique trace ID and creates a new context.
|
|
60
|
+
Sets the context as the active trace.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
root_api: The root API call (e.g., "POST /api/orders")
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
New TraceContext instance
|
|
67
|
+
"""
|
|
68
|
+
# Generate short UUID for readability (first 13 chars)
|
|
69
|
+
trace_id = str(uuid.uuid4())[:13]
|
|
70
|
+
ctx = cls(trace_id, root_api)
|
|
71
|
+
_trace_context.set(ctx)
|
|
72
|
+
return ctx
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
def get_current(cls) -> Optional['TraceContext']:
|
|
76
|
+
"""
|
|
77
|
+
Get the current active trace context.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Active TraceContext or None if no trace is active
|
|
81
|
+
"""
|
|
82
|
+
return _trace_context.get()
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def end_trace(cls) -> Optional[TraceBuffer]:
|
|
86
|
+
"""
|
|
87
|
+
End the current trace and return the buffer.
|
|
88
|
+
|
|
89
|
+
Clears the active context.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
TraceBuffer containing all trace entries, or None if no active trace
|
|
93
|
+
"""
|
|
94
|
+
ctx = _trace_context.get()
|
|
95
|
+
if ctx:
|
|
96
|
+
_trace_context.set(None)
|
|
97
|
+
return ctx.buffer
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
def push_call(self, func_name: str) -> int:
|
|
101
|
+
"""
|
|
102
|
+
Push a function call onto the stack.
|
|
103
|
+
|
|
104
|
+
Increments depth and tracks the function name.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
func_name: Name of the function being called
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
Depth level before increment (for logging)
|
|
111
|
+
"""
|
|
112
|
+
self._call_stack.append(func_name)
|
|
113
|
+
depth = self.depth
|
|
114
|
+
self.depth += 1
|
|
115
|
+
return depth
|
|
116
|
+
|
|
117
|
+
def pop_call(self) -> None:
|
|
118
|
+
"""
|
|
119
|
+
Pop a function call from the stack.
|
|
120
|
+
|
|
121
|
+
Decrements depth and removes the function from tracking.
|
|
122
|
+
"""
|
|
123
|
+
if self._call_stack:
|
|
124
|
+
self._call_stack.pop()
|
|
125
|
+
self.depth -= 1
|