Skip to content

Commit 4cd76a3

Browse files
Initial: yoga-jaeger
0 parents  commit 4cd76a3

File tree

7 files changed

+584
-0
lines changed

7 files changed

+584
-0
lines changed

.github/workflows/ci.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name: CI
2+
on: [push, pull_request]
3+
jobs:
4+
build:
5+
runs-on: ubuntu-latest
6+
steps:
7+
- uses: actions/checkout@v4
8+
- uses: rowtype-yoga/purescript-yoga-actions/.github/actions/setup@main
9+
- run: spago build

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules/
2+
.spago/
3+
output*/

package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "purescript-yoga-jaeger",
3+
"version": "0.1.0",
4+
"description": "PureScript FFI bindings for Jaeger tracing",
5+
"license": "MIT",
6+
"repository": {
7+
"type": "git",
8+
"url": "https://github.com/rowtype-yoga/purescript-yoga-backend-stack.git",
9+
"directory": "packages/yoga-jaeger"
10+
},
11+
"keywords": ["purescript", "ffi", "bindings", "yoga"]
12+
}

spago.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
workspace:
2+
package_set:
3+
registry: 51.1.0
4+
5+
package:
6+
name: yoga-jaeger
7+
publish:
8+
version: 0.1.0
9+
license: MIT
10+
location:
11+
githubOwner: rowtype-yoga
12+
githubRepo: purescript-yoga-jaeger
13+
dependencies:
14+
- js-promise: ">=1.0.0 <2.0.0"
15+
- js-promise-aff: ">=1.0.0 <2.0.0"
16+
- aff: ">=7.0.0 <8.0.0"
17+
- effect: ">=4.0.0 <5.0.0"
18+
- foreign-object: ">=4.0.0 <5.0.0"
19+
- newtype: ">=5.0.0 <6.0.0"
20+
- nullable: ">=6.0.0 <7.0.0"
21+
- prelude: ">=6.0.0 <7.0.0"
22+
test:
23+
main: Test.Jaeger.Main
24+
dependencies:
25+
- spec: ">=7.0.0 <8.0.0"

src/Yoga/Jaeger/Jaeger.js

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
const { initTracer: jaegerInitTracer } = require('jaeger-client');
2+
3+
// Initialize tracer
4+
export const initTracerImpl = (config) => {
5+
const tracerConfig = {
6+
serviceName: config.serviceName || 'unknown-service',
7+
sampler: config.sampler || {
8+
type: 'const',
9+
param: 1,
10+
},
11+
reporter: config.reporter || {
12+
logSpans: false,
13+
},
14+
};
15+
16+
// Optional configuration
17+
if (config.traceId128bit !== undefined) {
18+
tracerConfig.traceId128bit = config.traceId128bit;
19+
}
20+
21+
if (config.shareRpcSpan !== undefined) {
22+
tracerConfig.shareRpcSpan = config.shareRpcSpan;
23+
}
24+
25+
const options = {};
26+
27+
return jaegerInitTracer(tracerConfig, options);
28+
};
29+
30+
// Start span
31+
export const startSpanImpl = (tracer, operationName, options) => {
32+
const spanOptions = {};
33+
34+
// Handle childOf
35+
if (options.childOf) {
36+
spanOptions.childOf = options.childOf;
37+
}
38+
39+
// Handle references - array of { refType, spanContext }
40+
if (options.references) {
41+
spanOptions.references = options.references.map(ref => {
42+
const refType = ref.refType; // SpanReferenceType ADT
43+
const type = refType.constructor.name === 'ChildOf' ? 'child_of' : 'follows_from';
44+
return tracer.reference(type, ref.spanContext);
45+
});
46+
}
47+
48+
// Handle tags - Object TagValue
49+
if (options.tags) {
50+
const jsTags = {};
51+
for (const [key, tagValue] of Object.entries(options.tags)) {
52+
jsTags[key] = tagValueToJS(tagValue);
53+
}
54+
spanOptions.tags = jsTags;
55+
}
56+
57+
// Handle startTime - Instant is milliseconds since epoch
58+
if (options.startTime !== undefined) {
59+
spanOptions.startTime = options.startTime;
60+
}
61+
62+
return tracer.startSpan(operationName, spanOptions);
63+
};
64+
65+
// Start span as child
66+
export const startSpanAsChildImpl = (tracer, operationName, parentSpan) => {
67+
return tracer.startSpan(operationName, {
68+
childOf: parentSpan.context(),
69+
});
70+
};
71+
72+
// Get span context
73+
export const getSpanContextImpl = (span) => {
74+
return span.context();
75+
};
76+
77+
// Convert TagValue ADT to JS value
78+
const tagValueToJS = (tagValue) => {
79+
// TagValue is an ADT: TagString, TagNumber, or TagBoolean
80+
if (tagValue.constructor.name === 'TagString') {
81+
return tagValue.value0;
82+
} else if (tagValue.constructor.name === 'TagNumber') {
83+
return tagValue.value0;
84+
} else if (tagValue.constructor.name === 'TagBoolean') {
85+
return tagValue.value0;
86+
}
87+
return tagValue; // fallback
88+
};
89+
90+
// Set tag
91+
export const setTagImpl = (span, key, tagValue) => {
92+
span.setTag(key, tagValueToJS(tagValue));
93+
};
94+
95+
// Set multiple tags - convert Object TagValue to Object of JS values
96+
export const setTagsImpl = (span, tags) => {
97+
const jsTags = {};
98+
for (const [key, tagValue] of Object.entries(tags)) {
99+
jsTags[key] = tagValueToJS(tagValue);
100+
}
101+
span.addTags(jsTags);
102+
};
103+
104+
// Log
105+
export const logImpl = (span, fields) => {
106+
span.log(fields);
107+
};
108+
109+
// Log with timestamp - Instant is milliseconds since epoch
110+
export const logWithTimestampImpl = (span, fields, instant) => {
111+
// Instant is a newtype wrapping milliseconds (Number)
112+
const timestamp = instant;
113+
span.log(fields, timestamp);
114+
};
115+
116+
// Set baggage item
117+
export const setBaggageItemImpl = (span, key, value) => {
118+
span.setBaggageItem(key, value);
119+
};
120+
121+
// Get baggage item
122+
export const getBaggageItemImpl = (span, key) => {
123+
return span.getBaggageItem(key) || null;
124+
};
125+
126+
// Set operation name
127+
export const setOperationNameImpl = (span, operationName) => {
128+
span.setOperationName(operationName);
129+
};
130+
131+
// Finish span
132+
export const finishSpanImpl = (span) => {
133+
span.finish();
134+
};
135+
136+
// Finish span with timestamp - Instant is milliseconds since epoch
137+
export const finishSpanWithTimestampImpl = (span, instant) => {
138+
const timestamp = instant;
139+
span.finish(timestamp);
140+
};
141+
142+
// Close tracer
143+
export const closeTracerImpl = (tracer) => {
144+
return new Promise((resolve, reject) => {
145+
tracer.close((err) => {
146+
if (err) {
147+
reject(err);
148+
} else {
149+
resolve();
150+
}
151+
});
152+
});
153+
};
154+
155+
// Inject span context into carrier - returns Object String
156+
export const injectImpl = (tracer, spanContext, format) => {
157+
const carrier = {};
158+
tracer.inject(spanContext, format, carrier);
159+
return carrier;
160+
};
161+
162+
// Extract span context from carrier - takes Object String
163+
export const extractImpl = (tracer, format, carrier) => {
164+
return tracer.extract(format, carrier) || null;
165+
};

0 commit comments

Comments
 (0)