ma-agents 1.7.0 → 1.9.0
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.
- package/bin/cli.js +98 -28
- package/out.txt +0 -0
- package/package.json +1 -1
- package/skills/README.md +24 -0
- package/skills/cpp-memory-handling/SKILL.md +38 -0
- package/skills/cpp-memory-handling/examples/modern-cpp.md +49 -0
- package/skills/cpp-memory-handling/examples/smart-pointers.md +46 -0
- package/skills/cpp-memory-handling/skill.json +20 -0
- package/skills/opentelemetry-best-practices/SKILL.md +30 -0
- package/skills/opentelemetry-best-practices/examples/go.md +32 -0
- package/skills/opentelemetry-best-practices/examples/javascript.md +58 -0
- package/skills/opentelemetry-best-practices/examples/python.md +37 -0
- package/skills/opentelemetry-best-practices/references/otel-standards.md +37 -0
- package/skills/opentelemetry-best-practices/skill.json +19 -0
package/bin/cli.js
CHANGED
|
@@ -120,60 +120,113 @@ async function installWizard(preselectedSkill, preselectedAgents, customPath, fo
|
|
|
120
120
|
const skills = listSkills();
|
|
121
121
|
const agents = listAgents();
|
|
122
122
|
|
|
123
|
+
let selectedSkillIds = preselectedSkill ? [preselectedSkill] : [];
|
|
124
|
+
let selectedAgentIds = preselectedAgents || [];
|
|
125
|
+
let installScope = 'project';
|
|
126
|
+
let installPath = customPath || '';
|
|
127
|
+
|
|
128
|
+
const existingStatus = getStatus([], '', 'project');
|
|
129
|
+
let isUpdate = false;
|
|
130
|
+
|
|
131
|
+
// Step 0: Check for existing installation ONLY in interactive mode (no preselected skill)
|
|
132
|
+
if (!preselectedSkill && !customPath && existingStatus.length > 0) {
|
|
133
|
+
console.log(chalk.cyan('\n Existing installation detected in project.'));
|
|
134
|
+
|
|
135
|
+
const { action } = await prompts({
|
|
136
|
+
type: 'select',
|
|
137
|
+
name: 'action',
|
|
138
|
+
message: 'What would you like to do?',
|
|
139
|
+
choices: [
|
|
140
|
+
{ title: 'Update (add/remove skills)', value: 'update' },
|
|
141
|
+
{ title: 'Clean reinstall (remove all first)', value: 'reinstall' },
|
|
142
|
+
{ title: 'Uninstall all skills', value: 'uninstall' },
|
|
143
|
+
{ title: 'Cancel', value: 'cancel' }
|
|
144
|
+
]
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
if (!action || action === 'cancel') process.exit(0);
|
|
148
|
+
|
|
149
|
+
if (action === 'uninstall') {
|
|
150
|
+
const { confirmed } = await prompts({
|
|
151
|
+
type: 'confirm',
|
|
152
|
+
name: 'confirmed',
|
|
153
|
+
message: 'This will remove all ma-agents skills from this project. Are you sure?',
|
|
154
|
+
initial: false
|
|
155
|
+
});
|
|
156
|
+
if (!confirmed) process.exit(0);
|
|
157
|
+
|
|
158
|
+
for (const entry of existingStatus) {
|
|
159
|
+
for (const skillId of Object.keys(entry.skills)) {
|
|
160
|
+
await uninstallSkill(skillId, [entry.agent.id], '', 'project');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
console.log(chalk.bold.green('\n All skills successfully removed!\n'));
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (action === 'reinstall') {
|
|
168
|
+
for (const entry of existingStatus) {
|
|
169
|
+
for (const skillId of Object.keys(entry.skills)) {
|
|
170
|
+
await uninstallSkill(skillId, [entry.agent.id], '', 'project');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
console.log(chalk.gray(' Clean slate prepared.'));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (action === 'update') {
|
|
177
|
+
isUpdate = true;
|
|
178
|
+
// Pre-populate selections from existing status
|
|
179
|
+
const existingSkillIds = new Set();
|
|
180
|
+
const existingAgentIds = new Set();
|
|
181
|
+
existingStatus.forEach(entry => {
|
|
182
|
+
existingAgentIds.add(entry.agent.id);
|
|
183
|
+
Object.keys(entry.skills).forEach(id => existingSkillIds.add(id));
|
|
184
|
+
});
|
|
185
|
+
selectedSkillIds = Array.from(existingSkillIds);
|
|
186
|
+
selectedAgentIds = Array.from(existingAgentIds);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
123
190
|
// Step 1: Select skills
|
|
124
|
-
|
|
125
|
-
if (preselectedSkill) {
|
|
126
|
-
selectedSkillIds = [preselectedSkill];
|
|
127
|
-
} else {
|
|
191
|
+
if (selectedSkillIds.length === 0 || isUpdate) {
|
|
128
192
|
const { skills: chosen } = await prompts({
|
|
129
193
|
type: 'multiselect',
|
|
130
194
|
name: 'skills',
|
|
131
|
-
message: '
|
|
195
|
+
message: 'Select the skills you want to have installed:',
|
|
132
196
|
choices: skills.map(s => ({
|
|
133
197
|
title: chalk.white(s.name) + chalk.gray(` v${s.version} - ${s.description}`),
|
|
134
198
|
value: s.id,
|
|
135
|
-
selected:
|
|
199
|
+
selected: selectedSkillIds.includes(s.id)
|
|
136
200
|
})),
|
|
137
201
|
instructions: chalk.gray(' Use space to select, enter to confirm'),
|
|
138
202
|
min: 1
|
|
139
203
|
});
|
|
140
204
|
|
|
141
|
-
if (!chosen
|
|
142
|
-
console.log(chalk.yellow('No skills selected. Exiting.'));
|
|
143
|
-
process.exit(0);
|
|
144
|
-
}
|
|
205
|
+
if (!chosen) process.exit(0);
|
|
145
206
|
selectedSkillIds = chosen;
|
|
146
207
|
}
|
|
147
208
|
|
|
148
209
|
// Step 2: Select agents
|
|
149
|
-
|
|
150
|
-
if (preselectedAgents && preselectedAgents.length > 0) {
|
|
151
|
-
selectedAgentIds = preselectedAgents;
|
|
152
|
-
} else {
|
|
210
|
+
if (selectedAgentIds.length === 0 || isUpdate) {
|
|
153
211
|
const { agents: chosen } = await prompts({
|
|
154
212
|
type: 'multiselect',
|
|
155
213
|
name: 'agents',
|
|
156
|
-
message: '
|
|
214
|
+
message: 'Select which coding agents to include:',
|
|
157
215
|
choices: agents.map(a => ({
|
|
158
216
|
title: chalk.white(a.name) + chalk.gray(` v${a.version} - ${a.description}`),
|
|
159
217
|
value: a.id,
|
|
160
|
-
selected:
|
|
218
|
+
selected: selectedAgentIds.includes(a.id)
|
|
161
219
|
})),
|
|
162
220
|
instructions: chalk.gray(' Use space to select, enter to confirm'),
|
|
163
221
|
min: 1
|
|
164
222
|
});
|
|
165
223
|
|
|
166
|
-
if (!chosen
|
|
167
|
-
console.log(chalk.yellow('No agents selected. Exiting.'));
|
|
168
|
-
process.exit(0);
|
|
169
|
-
}
|
|
224
|
+
if (!chosen) process.exit(0);
|
|
170
225
|
selectedAgentIds = chosen;
|
|
171
226
|
}
|
|
172
227
|
|
|
173
|
-
// Step 3:
|
|
174
|
-
|
|
175
|
-
let installScope = 'project';
|
|
176
|
-
if (!installPath) {
|
|
228
|
+
// Step 3: Scope (Skip if update, we already know it's project)
|
|
229
|
+
if (!isUpdate && !installPath) {
|
|
177
230
|
const { pathChoice } = await prompts({
|
|
178
231
|
type: 'select',
|
|
179
232
|
name: 'pathChoice',
|
|
@@ -209,16 +262,33 @@ async function installWizard(preselectedSkill, preselectedAgents, customPath, fo
|
|
|
209
262
|
const { confirmed } = await prompts({
|
|
210
263
|
type: 'confirm',
|
|
211
264
|
name: 'confirmed',
|
|
212
|
-
message: 'Proceed with installation?',
|
|
265
|
+
message: isUpdate ? 'Apply changes?' : 'Proceed with installation?',
|
|
213
266
|
initial: true
|
|
214
267
|
});
|
|
215
268
|
|
|
216
269
|
if (!confirmed) {
|
|
217
|
-
console.log(chalk.yellow('
|
|
270
|
+
console.log(chalk.yellow('Operation cancelled.'));
|
|
218
271
|
process.exit(0);
|
|
219
272
|
}
|
|
220
273
|
|
|
221
|
-
// Step 5:
|
|
274
|
+
// Step 5: Execution
|
|
275
|
+
if (isUpdate) {
|
|
276
|
+
// Identify removals
|
|
277
|
+
const currentlyInstalled = new Set();
|
|
278
|
+
existingStatus.forEach(entry => Object.keys(entry.skills).forEach(id => currentlyInstalled.add(id)));
|
|
279
|
+
|
|
280
|
+
const finalSkills = new Set(selectedSkillIds);
|
|
281
|
+
const toRemove = [...currentlyInstalled].filter(id => !finalSkills.has(id));
|
|
282
|
+
|
|
283
|
+
if (toRemove.length > 0) {
|
|
284
|
+
console.log(chalk.gray(`\n Cleaning up ${toRemove.length} removed skills...`));
|
|
285
|
+
for (const skillId of toRemove) {
|
|
286
|
+
await uninstallSkill(skillId, selectedAgentIds, installPath, 'project');
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Install requested skills
|
|
222
292
|
for (const skillId of selectedSkillIds) {
|
|
223
293
|
try {
|
|
224
294
|
await installSkill(skillId, selectedAgentIds, installPath, installScope, { force: !!forceFlag });
|
|
@@ -227,7 +297,7 @@ async function installWizard(preselectedSkill, preselectedAgents, customPath, fo
|
|
|
227
297
|
}
|
|
228
298
|
}
|
|
229
299
|
|
|
230
|
-
console.log(chalk.bold.green('\n
|
|
300
|
+
console.log(chalk.bold.green('\n Done!\n'));
|
|
231
301
|
}
|
|
232
302
|
|
|
233
303
|
// --- Command handlers ---
|
package/out.txt
ADDED
|
Binary file
|
package/package.json
CHANGED
package/skills/README.md
CHANGED
|
@@ -216,6 +216,30 @@ Standardizes structured logging (JSON) across Backend, Frontend, Realtime, and A
|
|
|
216
216
|
|
|
217
217
|
---
|
|
218
218
|
|
|
219
|
+
### 7. OpenTelemetry Best Practices
|
|
220
|
+
**Directory:** `opentelemetry-best-practices/`
|
|
221
|
+
|
|
222
|
+
Standardizes distributed tracing, metrics, and semantic conventions for high-quality system observability. Enforces trace context propagation and OTel semantic naming.
|
|
223
|
+
|
|
224
|
+
**Key Features:**
|
|
225
|
+
- ✅ **Standardized Tracing**: Mandates spans for DB calls and external requests.
|
|
226
|
+
- ✅ **Semantic Conventions**: Enforces OTel naming standards.
|
|
227
|
+
- ✅ **Context Propagation**: Ensures trace IDs flow across async boundaries.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
### 8. C++ Safe Memory Handling
|
|
232
|
+
**Directory:** `cpp-memory-handling/`
|
|
233
|
+
|
|
234
|
+
Enforces Modern C++ practices (RAII, Smart Pointers) to prevent memory leaks and dangling pointers.
|
|
235
|
+
|
|
236
|
+
**Key Features:**
|
|
237
|
+
- ✅ **Smart Pointers**: Mandates `std::unique_ptr` and `std::shared_ptr`.
|
|
238
|
+
- ✅ **RAII**: Ensures every resource is bound to object lifetimes.
|
|
239
|
+
- ✅ **Safe Containers**: Forbids raw buffers in favor of `std::vector` and `std::string`.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
219
243
|
## Requirements
|
|
220
244
|
|
|
221
245
|
### All Skills
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# C++ Safe Memory Handling
|
|
2
|
+
|
|
3
|
+
Guidelines for writing robust, memory-safe C++ code by leveraging Modern C++ features and RAII principles.
|
|
4
|
+
|
|
5
|
+
## Mandatory Policies
|
|
6
|
+
|
|
7
|
+
### 1. Smart Pointers by Default
|
|
8
|
+
You MUST use smart pointers for all heap allocations.
|
|
9
|
+
- Use `std::unique_ptr` for exclusive ownership. This is the preferred default.
|
|
10
|
+
- Use `std::shared_ptr` only when multiple objects share ownership of a resource.
|
|
11
|
+
- Use `std::weak_ptr` to break circular dependencies or for non-owning references that must be checked for validity.
|
|
12
|
+
|
|
13
|
+
### 2. Forbid raw new/delete
|
|
14
|
+
You MUST NOT use raw `new` and `delete` operators.
|
|
15
|
+
- Use `std::make_unique` (C++14+) or `std::make_shared` to allocate objects on the heap.
|
|
16
|
+
- Exceptions are only allowed within low-level custom container implementations, which must be encapsulated.
|
|
17
|
+
|
|
18
|
+
### 3. Prefer Value Semantics
|
|
19
|
+
Always prefer stack-allocated objects and value semantics over pointer-based indirection unless heap allocation is strictly necessary (e.g., polymorphism, very large objects, or dynamic lifetimes).
|
|
20
|
+
|
|
21
|
+
### 4. RAII for All Resources
|
|
22
|
+
Every resource (file handles, sockets, mutexes, memory) MUST be managed by an object whose constructor acquires the resource and destructor releases it. Never rely on manual cleanup blocks.
|
|
23
|
+
|
|
24
|
+
### 5. Standard Containers
|
|
25
|
+
NEVER use raw buffers or manually managed arrays.
|
|
26
|
+
- Use `std::vector` for dynamic arrays.
|
|
27
|
+
- Use `std::string` for text.
|
|
28
|
+
- Use `std::array` (C++11) for fixed-size stack arrays.
|
|
29
|
+
- Access elements using `.at()` if bounds checking is required for security-critical logic.
|
|
30
|
+
|
|
31
|
+
## Critical Rules
|
|
32
|
+
- **No Dangling Pointers**: Never return a pointer or reference to a local stack-allocated variable.
|
|
33
|
+
- **Rule of Zero/Five**: Follow the "Rule of Zero" (prefer components that handle their own resource management). If manual management is needed, correctly implement the "Rule of Five".
|
|
34
|
+
- **Nullable Checks**: Always check pointers (even smart ones) for `nullptr` before dereferencing if there is any chance they could be empty.
|
|
35
|
+
|
|
36
|
+
## Resources
|
|
37
|
+
- [Modern C++ Examples](file:///skills/cpp-memory-handling/examples/modern-cpp.md)
|
|
38
|
+
- [Smart Pointer Reference](file:///skills/cpp-memory-handling/examples/smart-pointers.md)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Modern C++ Safe Memory Examples
|
|
2
|
+
|
|
3
|
+
Demonstrating RAII and safe resource management in modern C++.
|
|
4
|
+
|
|
5
|
+
## RAII Resource Management
|
|
6
|
+
|
|
7
|
+
```cpp
|
|
8
|
+
#include <iostream>
|
|
9
|
+
#include <fstream>
|
|
10
|
+
#include <vector>
|
|
11
|
+
#include <memory>
|
|
12
|
+
|
|
13
|
+
class FileHandler {
|
|
14
|
+
public:
|
|
15
|
+
FileHandler(const std::string& filename) : file(filename) {
|
|
16
|
+
if (!file.is_open()) throw std::runtime_error("Could not open file");
|
|
17
|
+
}
|
|
18
|
+
// Destructor automatically closes the file
|
|
19
|
+
~FileHandler() { if (file.is_open()) file.close(); }
|
|
20
|
+
|
|
21
|
+
void write(const std::string& data) { file << data; }
|
|
22
|
+
|
|
23
|
+
private:
|
|
24
|
+
std::ofstream file;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
void log_data(const std::string& message) {
|
|
28
|
+
// RAII handles lifetime. No manual close needed.
|
|
29
|
+
FileHandler handler("app.log");
|
|
30
|
+
handler.write(message);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Vector vs Raw Arrays
|
|
35
|
+
|
|
36
|
+
```cpp
|
|
37
|
+
// BAD: Manual memory management
|
|
38
|
+
void bad_array() {
|
|
39
|
+
int* arr = new int[100];
|
|
40
|
+
// ... logic ...
|
|
41
|
+
delete[] arr; // Manual cleanup is error-prone
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// GOOD: Automatic memory management
|
|
45
|
+
void safe_vector() {
|
|
46
|
+
std::vector<int> arr(100);
|
|
47
|
+
// Vector manages its own heap memory. RAII cleans up at scope exit.
|
|
48
|
+
}
|
|
49
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# C++ Smart Pointer Reference
|
|
2
|
+
|
|
3
|
+
Guidelines for selecting and using smart pointers correctly.
|
|
4
|
+
|
|
5
|
+
## unique_ptr (Preferred Default)
|
|
6
|
+
- Represents **exclusive ownership**.
|
|
7
|
+
- Zero runtime overhead compared to raw pointers.
|
|
8
|
+
|
|
9
|
+
```cpp
|
|
10
|
+
#include <memory>
|
|
11
|
+
|
|
12
|
+
class Widget { /* ... */ };
|
|
13
|
+
|
|
14
|
+
void exclusive_use() {
|
|
15
|
+
// Use make_unique for safety and efficiency
|
|
16
|
+
auto widget = std::make_unique<Widget>();
|
|
17
|
+
|
|
18
|
+
// Ownership can be moved but not copied
|
|
19
|
+
std::unique_ptr<Widget> other = std::move(widget);
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## shared_ptr (For Shared Ownership)
|
|
24
|
+
- Use only when **multiple** owners truly exist.
|
|
25
|
+
- Reference counting has small overhead.
|
|
26
|
+
|
|
27
|
+
```cpp
|
|
28
|
+
void shared_use() {
|
|
29
|
+
auto shared_widget = std::make_shared<Widget>();
|
|
30
|
+
|
|
31
|
+
auto owner1 = shared_widget; // Count = 2
|
|
32
|
+
auto owner2 = shared_widget; // Count = 3
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## weak_ptr (Breaking Cycles)
|
|
37
|
+
- Non-owning reference. Must be locked before use.
|
|
38
|
+
|
|
39
|
+
```cpp
|
|
40
|
+
void weak_use(std::weak_ptr<Widget> weak_widget) {
|
|
41
|
+
if (auto shared = weak_widget.lock()) {
|
|
42
|
+
// Resource is still alive
|
|
43
|
+
shared->do_something();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "C++ Safe Memory Handling",
|
|
3
|
+
"description": "Enforces Modern C++ practices (RAII, Smart Pointers) to prevent memory leaks, dangling pointers, and buffer overflows.",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"author": "Antigravity",
|
|
6
|
+
"tags": [
|
|
7
|
+
"cpp",
|
|
8
|
+
"memory-management",
|
|
9
|
+
"raii",
|
|
10
|
+
"smart-pointers",
|
|
11
|
+
"cplusplus",
|
|
12
|
+
"security"
|
|
13
|
+
],
|
|
14
|
+
"applies_when": [
|
|
15
|
+
"writing c++ code",
|
|
16
|
+
"modifying memory-intensive C++ logic",
|
|
17
|
+
"debugging memory leaks in c++",
|
|
18
|
+
"implementing new c++ classes"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# OpenTelemetry Best Practices
|
|
2
|
+
|
|
3
|
+
Guidelines for implementing standardized distributed tracing and metrics using OpenTelemetry to ensure high-quality observability.
|
|
4
|
+
|
|
5
|
+
## Mandatory Policies
|
|
6
|
+
|
|
7
|
+
### 1. Semantic Conventions
|
|
8
|
+
You MUST use OpenTelemetry Semantic Conventions for all attribute names. Never invent custom names for standard concepts (e.g., use `http.method` instead of `method` or `http_method`).
|
|
9
|
+
|
|
10
|
+
### 2. Context Propagation
|
|
11
|
+
You MUST ensure trace context is propagated across asynchronous boundaries. When starting a background task or making a network call, ensure the active span is correctly parented or the context is injected into headers.
|
|
12
|
+
|
|
13
|
+
### 3. Span Granularity
|
|
14
|
+
- **Database**: Every query MUST have its own span with attributes for the statement (sanitized) and database name.
|
|
15
|
+
- **External API**: Every outgoing request MUST have a span.
|
|
16
|
+
- **Complex Logic**: Large internal computation blocks SHOULD have spans if they represent a distinct logical step.
|
|
17
|
+
|
|
18
|
+
### 4. Meaningful Metrics
|
|
19
|
+
- **Counters**: Use for discrete events (e.g., `api.requests.total`).
|
|
20
|
+
- **Histograms**: Use for durations and sizes (e.g., `api.latency`).
|
|
21
|
+
- **Attributes**: Common attributes (e.g., `status_code`, `service.name`) SHOULD be applied to both spans and metrics.
|
|
22
|
+
|
|
23
|
+
## Critical Rules
|
|
24
|
+
- **No Sensitive Data**: Never include PII, passwords, or tokens in span attributes or logs associated with spans.
|
|
25
|
+
- **Fail Gracefully**: Instrumentation should never crash the application. Use `tracer.startActiveSpan` carefully with `try...finally` to ensure spans are always ended.
|
|
26
|
+
- **Status Codes**: Always set the span status to `Error` when an exception is caught that isn't handled.
|
|
27
|
+
|
|
28
|
+
## Resources
|
|
29
|
+
- [Semantic Conventions Reference](file:///skills/opentelemetry-best-practices/references/otel-standards.md)
|
|
30
|
+
- [Example Implementations](file:///skills/opentelemetry-best-practices/examples/javascript.md)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# OpenTelemetry Go Examples
|
|
2
|
+
|
|
3
|
+
Idiomatic usage of the OpenTelemetry Go SDK.
|
|
4
|
+
|
|
5
|
+
## Context-Aware Tracing
|
|
6
|
+
|
|
7
|
+
```go
|
|
8
|
+
import (
|
|
9
|
+
"context"
|
|
10
|
+
"go.opentelemetry.io/otel"
|
|
11
|
+
"go.opentelemetry.io/otel/attribute"
|
|
12
|
+
"go.opentelemetry.io/otel/codes"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
var tracer = otel.Tracer("my-service")
|
|
16
|
+
|
|
17
|
+
func (s *Server) GetUser(ctx context.Context, id string) (*User, error) {
|
|
18
|
+
ctx, span := tracer.Start(ctx, "GetUser")
|
|
19
|
+
defer span.End()
|
|
20
|
+
|
|
21
|
+
span.SetAttributes(attribute.String("user.id", id))
|
|
22
|
+
|
|
23
|
+
user, err := s.db.FetchUser(ctx, id)
|
|
24
|
+
if err != nil {
|
|
25
|
+
span.RecordError(err)
|
|
26
|
+
span.SetStatus(codes.Error, err.Error())
|
|
27
|
+
return nil, err
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return user, nil
|
|
31
|
+
}
|
|
32
|
+
```
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# OpenTelemetry JavaScript (Node.js) Examples
|
|
2
|
+
|
|
3
|
+
Idiomatic usage of the OpenTelemetry SDK in Node.js applications.
|
|
4
|
+
|
|
5
|
+
## Tracing a Function
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
const { trace } = require('@opentelemetry/api');
|
|
9
|
+
|
|
10
|
+
const tracer = trace.getTracer('my-service');
|
|
11
|
+
|
|
12
|
+
async function processOrder(orderId) {
|
|
13
|
+
// Use startActiveSpan to automatically handle context propagation
|
|
14
|
+
return tracer.startActiveSpan('process.order', async (span) => {
|
|
15
|
+
try {
|
|
16
|
+
// Set semantic attributes
|
|
17
|
+
span.setAttribute('order.id', orderId);
|
|
18
|
+
|
|
19
|
+
const result = await someDatabaseCall(orderId);
|
|
20
|
+
|
|
21
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
22
|
+
return result;
|
|
23
|
+
} catch (error) {
|
|
24
|
+
span.recordException(error);
|
|
25
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
|
|
26
|
+
throw error;
|
|
27
|
+
} finally {
|
|
28
|
+
span.end();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Creating Metrics
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
const { metrics } = require('@opentelemetry/api');
|
|
38
|
+
|
|
39
|
+
const meter = metrics.getMeter('my-service');
|
|
40
|
+
|
|
41
|
+
const requestCounter = meter.createCounter('api.requests.total', {
|
|
42
|
+
description: 'Total number of API requests',
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const latencyHistogram = meter.createHistogram('api.latency', {
|
|
46
|
+
description: 'API request latency',
|
|
47
|
+
unit: 'ms',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
function handleRequest(req) {
|
|
51
|
+
const startTime = Date.now();
|
|
52
|
+
|
|
53
|
+
// Logic...
|
|
54
|
+
|
|
55
|
+
requestCounter.add(1, { 'http.method': req.method, 'status_code': 200 });
|
|
56
|
+
latencyHistogram.record(Date.now() - startTime, { 'http.method': req.method });
|
|
57
|
+
}
|
|
58
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# OpenTelemetry Python Examples
|
|
2
|
+
|
|
3
|
+
Idiomatic usage of the OpenTelemetry Python SDK.
|
|
4
|
+
|
|
5
|
+
## Tracing with Decorators
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from opentelemetry import trace
|
|
9
|
+
|
|
10
|
+
tracer = trace.get_tracer(__name__)
|
|
11
|
+
|
|
12
|
+
@tracer.start_as_current_span("process_data")
|
|
13
|
+
def process_data(data):
|
|
14
|
+
span = trace.get_current_span()
|
|
15
|
+
span.set_attribute("data.size", len(data))
|
|
16
|
+
|
|
17
|
+
# Process...
|
|
18
|
+
return True
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Manual Span Management
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
def fetch_external_resource(url):
|
|
25
|
+
with tracer.start_as_current_span("http_request") as span:
|
|
26
|
+
span.set_attribute("http.url", url)
|
|
27
|
+
span.set_attribute("http.method", "GET")
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
response = requests.get(url)
|
|
31
|
+
span.set_attribute("http.status_code", response.status_code)
|
|
32
|
+
return response.json()
|
|
33
|
+
except Exception as e:
|
|
34
|
+
span.record_exception(e)
|
|
35
|
+
span.set_status(trace.Status(trace.StatusCode.ERROR))
|
|
36
|
+
raise
|
|
37
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# OpenTelemetry Standards & Semantic Conventions
|
|
2
|
+
|
|
3
|
+
This document outlines the specific attributes and naming conventions to follow when instrumenting services.
|
|
4
|
+
|
|
5
|
+
## Common Attributes
|
|
6
|
+
|
|
7
|
+
| Attribute | Description | Example |
|
|
8
|
+
|-----------|-------------|---------|
|
|
9
|
+
| `service.name` | Logical name of the service | `user-auth-service` |
|
|
10
|
+
| `service.version` | Version of the service | `1.2.3` |
|
|
11
|
+
| `deployment.environment` | Target environment | `production` |
|
|
12
|
+
|
|
13
|
+
## HTTP Semantic Conventions
|
|
14
|
+
|
|
15
|
+
| Attribute | Description | Example |
|
|
16
|
+
|-----------|-------------|---------|
|
|
17
|
+
| `http.method` | HTTP request method | `GET` |
|
|
18
|
+
| `http.status_code` | response status | `200` |
|
|
19
|
+
| `http.url` | Full request URL | `https://api.example.com/v1/users` |
|
|
20
|
+
| `http.user_agent` | User agent header | `Mozilla/5.0...` |
|
|
21
|
+
|
|
22
|
+
## Database Semantic Conventions
|
|
23
|
+
|
|
24
|
+
| Attribute | Description | Example |
|
|
25
|
+
|-----------|-------------|---------|
|
|
26
|
+
| `db.system` | Database vendor | `postgresql` |
|
|
27
|
+
| `db.statement` | Sanitized SQL/query | `SELECT * FROM users WHERE id = ?` |
|
|
28
|
+
| `db.name` | Database name | `prod_db` |
|
|
29
|
+
| `db.operation` | Operation name | `SELECT` |
|
|
30
|
+
|
|
31
|
+
## Span Status Values
|
|
32
|
+
- **Unset**: Default status.
|
|
33
|
+
- **Ok**: Explicitly marked as successful.
|
|
34
|
+
- **Error**: Encountered a failure. Describe the error in the `exception` event or attributes.
|
|
35
|
+
|
|
36
|
+
## Useful links
|
|
37
|
+
- [Official OTel Semantic Conventions](https://opentelemetry.io/docs/specs/otel/common/semantic-conventions/)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "OpenTelemetry Best Practices",
|
|
3
|
+
"description": "Standardizes distributed tracing, metrics, and semantic conventions for high-quality system observability.",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"author": "Antigravity",
|
|
6
|
+
"tags": [
|
|
7
|
+
"opentelemetry",
|
|
8
|
+
"observability",
|
|
9
|
+
"tracing",
|
|
10
|
+
"metrics",
|
|
11
|
+
"distributed-systems"
|
|
12
|
+
],
|
|
13
|
+
"applies_when": [
|
|
14
|
+
"implementing api endpoints",
|
|
15
|
+
"handling distributed requests",
|
|
16
|
+
"optimizing performance",
|
|
17
|
+
"adding monitoring"
|
|
18
|
+
]
|
|
19
|
+
}
|