rian 0.3.0-next.1 → 0.3.0-next.11
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/async.d.ts +59 -0
- package/async.js +1 -0
- package/async.mjs +1 -0
- package/exporter.otel.http.js +1 -0
- package/exporter.otel.http.mjs +1 -0
- package/exporter.zipkin.js +1 -0
- package/exporter.zipkin.mjs +1 -0
- package/index.d.ts +129 -65
- package/index.js +1 -1
- package/index.mjs +1 -1
- package/package.json +16 -10
- package/readme.md +129 -87
- package/utils.d.ts +25 -0
- package/utils.js +1 -0
- package/utils.mjs +1 -0
- package/exporter.otel.http/index.js +0 -1
- package/exporter.otel.http/index.mjs +0 -1
- package/exporter.zipkin/index.js +0 -1
- package/exporter.zipkin/index.mjs +0 -1
- package/utils/index.d.ts +0 -66
- package/utils/index.js +0 -1
- package/utils/index.mjs +0 -1
- /package/{exporter.otel.http/index.d.ts → exporter.otel.http.d.ts} +0 -0
- /package/{exporter.zipkin/index.d.ts → exporter.zipkin.d.ts} +0 -0
package/async.d.ts
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
import type { CallableScope, Options, Scope } from 'rian';
|
2
|
+
|
3
|
+
export { report, configure } from 'rian';
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Returns the current span in the current execution context.
|
7
|
+
*
|
8
|
+
* This will throw an error if there is no current span.
|
9
|
+
*
|
10
|
+
* @example
|
11
|
+
*
|
12
|
+
* ```ts
|
13
|
+
* function doWork() {
|
14
|
+
* const span = currentSpan();
|
15
|
+
* span.set_context({ foo: 'bar' });
|
16
|
+
* }
|
17
|
+
*
|
18
|
+
* span('some-name')(() => {
|
19
|
+
* doWork(); // will guarantee `currentSpan` returns this span
|
20
|
+
* });
|
21
|
+
* ```
|
22
|
+
*/
|
23
|
+
export function currentSpan(): Scope;
|
24
|
+
|
25
|
+
/**
|
26
|
+
* Creates a new span for the currently active tracer.
|
27
|
+
*
|
28
|
+
* @example
|
29
|
+
*
|
30
|
+
* ```ts
|
31
|
+
* tracer('some-name')(() => {
|
32
|
+
* // some deeply nested moments later
|
33
|
+
* const s = span('my-span');
|
34
|
+
* });
|
35
|
+
* ```
|
36
|
+
*/
|
37
|
+
export function span(name: string): CallableScope;
|
38
|
+
|
39
|
+
export type Tracer<T> = (cb: T) => ReturnType<T>;
|
40
|
+
|
41
|
+
/**
|
42
|
+
* A tracer is a logical unit in your application. This alleviates the need to pass around a tracer instance.
|
43
|
+
*
|
44
|
+
* All spans produced by a tracer will all collect into a single span collection that is given to {@link report}.
|
45
|
+
*
|
46
|
+
* @example
|
47
|
+
*
|
48
|
+
* ```ts
|
49
|
+
* const trace = tracer('server');
|
50
|
+
*
|
51
|
+
* trace(() => {
|
52
|
+
* // application logic
|
53
|
+
* });
|
54
|
+
* ```
|
55
|
+
*/
|
56
|
+
export function tracer<T extends () => any>(
|
57
|
+
name: string,
|
58
|
+
options?: Options,
|
59
|
+
): Tracer<T>;
|
package/async.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
const e = require('node:async_hooks');const { measure:t } = require('rian/utils');const { make:n, parse:r, SAMPLED_FLAG:o } = require('tctx');const { is_sampled:a } = require('tctx');var s={};function c(e,t={}){s={...t,"service.name":e,"telemetry.sdk.name":"rian","telemetry.sdk.version":"0.3.0-next.11"}}var l=new Set,i=new WeakMap;async function p(e){let t=[],n=new Map;for(let[e,r]of l){let o;n.has(r)?o=n.get(r).spans:n.set(r,{scope:r,spans:o=[]}),o.push(e),i.has(r)&&(t.push(...i.get(r)),i.delete(r))}return l.clear(),t.length&&await Promise.all(t),e({resource:s,scopeSpans:n.values()})}function u(e,t){return a(t)}var d=new e.AsyncLocalStorage;function m(){let e=d.getStore()?.[1];if(null==e)throw new Error("no current span");return e}function f(e){let r=d.getStore();if(!r)throw Error("TODO");let o=r[0],a=o.scope,s=r[1],c=o.sampler,p=s?.traceparent??o.root_id,u=p?p.child():n(),m="boolean"!=typeof c?c(e,u,a):c;u.flags;let w={id:u,parent:p,start:o.clock.now(),name:e,events:[],context:{}};m&&l.add([w,a]);let g=e=>d.run([o,g],t,g,e);g.traceparent=u,g.span=f,g.set_context=e=>{"function"!=typeof e?Object.assign(w.context,e):w.context=e(w.context)},g.add_event=(e,t)=>{w.events.push({name:e,timestamp:o.clock.now(),attributes:t||{}})},g.end=()=>{null==w.end&&(w.end=o.clock.now())};let h=i.get(a);return g.__add_promise=e=>{h.add(e),e.then((()=>h.delete(e)))},g}function w(e,t){let n=t?.sampler??u,o={name:e},a={root_id:"string"==typeof t?.traceparent?r(t.traceparent):void 0,scope:o,sampler:n,clock:t?.clock??Date};return i.set(o,new Set),function(e){let t=d.getStore();return a.root_id||(a.root_id=t?.[0].root_id),d.run([a,t?.[1]||null],e)}}exports.configure=c;exports.currentSpan=m;exports.report=p;exports.span=f;exports.tracer=w;
|
package/async.mjs
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
import*as e from"node:async_hooks";import{measure as t}from"rian/utils";import{make as n,parse as r,SAMPLED_FLAG as o}from"tctx";import{is_sampled as a}from"tctx";var s={};function c(e,t={}){s={...t,"service.name":e,"telemetry.sdk.name":"rian","telemetry.sdk.version":"0.3.0-next.11"}}var l=new Set,i=new WeakMap;async function p(e){let t=[],n=new Map;for(let[e,r]of l){let o;n.has(r)?o=n.get(r).spans:n.set(r,{scope:r,spans:o=[]}),o.push(e),i.has(r)&&(t.push(...i.get(r)),i.delete(r))}return l.clear(),t.length&&await Promise.all(t),e({resource:s,scopeSpans:n.values()})}function u(e,t){return a(t)}var d=new e.AsyncLocalStorage;function m(){let e=d.getStore()?.[1];if(null==e)throw new Error("no current span");return e}function f(e){let r=d.getStore();if(!r)throw Error("TODO");let o=r[0],a=o.scope,s=r[1],c=o.sampler,p=s?.traceparent??o.root_id,u=p?p.child():n(),m="boolean"!=typeof c?c(e,u,a):c;u.flags;let w={id:u,parent:p,start:o.clock.now(),name:e,events:[],context:{}};m&&l.add([w,a]);let g=e=>d.run([o,g],t,g,e);g.traceparent=u,g.span=f,g.set_context=e=>{"function"!=typeof e?Object.assign(w.context,e):w.context=e(w.context)},g.add_event=(e,t)=>{w.events.push({name:e,timestamp:o.clock.now(),attributes:t||{}})},g.end=()=>{null==w.end&&(w.end=o.clock.now())};let h=i.get(a);return g.__add_promise=e=>{h.add(e),e.then((()=>h.delete(e)))},g}function w(e,t){let n=t?.sampler??u,o={name:e},a={root_id:"string"==typeof t?.traceparent?r(t.traceparent):void 0,scope:o,sampler:n,clock:t?.clock??Date};return i.set(o,new Set),function(e){let t=d.getStore();return a.root_id||(a.root_id=t?.[0].root_id),d.run([a,t?.[1]||null],e)}}export{c as configure,m as currentSpan,p as report,f as span,w as tracer};
|
@@ -0,0 +1 @@
|
|
1
|
+
var e=r=>{let a=typeof r,s={};return"string"===a?s.stringValue=r:"number"===a?Number.isInteger(r)?s.intValue=r:s.doubleValue=r:"boolean"===a?s.boolValue=r:Array.isArray(r)?s.arrayValue={values:r.map((t=>e(t)))}:r&&(s.kvlistValue={values:t(r)}),s},t=t=>{let r=[];for(let a of Object.keys(t))r.push({key:a,value:e(t[a])});return r},r=e=>{switch(e){default:case"INTERNAL":return 1;case"SERVER":return 2;case"CLIENT":return 3;case"PRODUCER":return 4;case"CONSUMER":return 5}},a=e=>a=>{let s=[];for(let e of a.scopeSpans){let a=[];s.push({scope:e.scope,spans:a});for(let s of e.spans){let e,{kind:n,error:u,...o}=s.context;u&&(e={code:2},"message"in u&&(e.message=u.message)),a.push({traceId:s.id.trace_id,spanId:s.id.parent_id,parentSpanId:s.parent?.parent_id,name:s.name,kind:r(n||"INTERNAL"),startTimeUnixNano:1e6*s.start,endTimeUnixNano:s.end?1e6*s.end:void 0,droppedAttributesCount:0,droppedEventsCount:0,droppedLinksCount:0,attributes:t(o),status:e||{code:0},events:s.events.map((e=>({name:e.name,attributes:t(e.attributes),droppedAttributesCount:0,timeUnixNano:1e6*e.timestamp})))})}}return e({resourceSpans:[{resource:{attributes:t(a.resource),droppedAttributesCount:0},scopeSpans:s}]})};exports.exporter=a;
|
@@ -0,0 +1 @@
|
|
1
|
+
var e=r=>{let a=typeof r,s={};return"string"===a?s.stringValue=r:"number"===a?Number.isInteger(r)?s.intValue=r:s.doubleValue=r:"boolean"===a?s.boolValue=r:Array.isArray(r)?s.arrayValue={values:r.map((t=>e(t)))}:r&&(s.kvlistValue={values:t(r)}),s},t=t=>{let r=[];for(let a of Object.keys(t))r.push({key:a,value:e(t[a])});return r},r=e=>{switch(e){default:case"INTERNAL":return 1;case"SERVER":return 2;case"CLIENT":return 3;case"PRODUCER":return 4;case"CONSUMER":return 5}},a=e=>a=>{let s=[];for(let e of a.scopeSpans){let a=[];s.push({scope:e.scope,spans:a});for(let s of e.spans){let e,{kind:n,error:u,...o}=s.context;u&&(e={code:2},"message"in u&&(e.message=u.message)),a.push({traceId:s.id.trace_id,spanId:s.id.parent_id,parentSpanId:s.parent?.parent_id,name:s.name,kind:r(n||"INTERNAL"),startTimeUnixNano:1e6*s.start,endTimeUnixNano:s.end?1e6*s.end:void 0,droppedAttributesCount:0,droppedEventsCount:0,droppedLinksCount:0,attributes:t(o),status:e||{code:0},events:s.events.map((e=>({name:e.name,attributes:t(e.attributes),droppedAttributesCount:0,timeUnixNano:1e6*e.timestamp})))})}}return e({resourceSpans:[{resource:{attributes:t(a.resource),droppedAttributesCount:0},scopeSpans:s}]})};export{a as exporter};
|
@@ -0,0 +1 @@
|
|
1
|
+
const { flattie:e } = require('flattie');var t=t=>a=>{let r=[];for(let t of a.scopeSpans)for(let n of t.spans){let{kind:s,error:i,...o}=n.context;i&&(o.error=!("message"in i)||{name:i.name,message:i.message,stack:i.stack}),r.push({id:n.id.parent_id,traceId:n.id.trace_id,parentId:n.parent?n.parent.parent_id:void 0,name:n.name,kind:"INTERNAL"===s?void 0:s,timestamp:1e3*n.start,duration:n.end?1e3*(n.end-n.start):void 0,localEndpoint:{serviceName:`${a.resource["service.name"]}@${t.scope.name}`},tags:e({...a.resource,...o},".",!0),annotations:n.events.map((e=>({value:`${e.name} :: ${JSON.stringify(e.attributes)}`,timestamp:1e3*e.timestamp})))})}return t(r)};exports.exporter=t;
|
@@ -0,0 +1 @@
|
|
1
|
+
import{flattie as e}from"flattie";var t=t=>a=>{let r=[];for(let t of a.scopeSpans)for(let n of t.spans){let{kind:s,error:i,...o}=n.context;i&&(o.error=!("message"in i)||{name:i.name,message:i.message,stack:i.stack}),r.push({id:n.id.parent_id,traceId:n.id.trace_id,parentId:n.parent?n.parent.parent_id:void 0,name:n.name,kind:"INTERNAL"===s?void 0:s,timestamp:1e3*n.start,duration:n.end?1e3*(n.end-n.start):void 0,localEndpoint:{serviceName:`${a.resource["service.name"]}@${t.scope.name}`},tags:e({...a.resource,...o},".",!0),annotations:n.events.map((e=>({value:`${e.name} :: ${JSON.stringify(e.attributes)}`,timestamp:1e3*e.timestamp})))})}return t(r)};export{t as exporter};
|
package/index.d.ts
CHANGED
@@ -1,31 +1,91 @@
|
|
1
1
|
import type { Traceparent } from 'tctx';
|
2
2
|
|
3
|
+
// --- tracer
|
4
|
+
|
5
|
+
/**
|
6
|
+
* The exporter is called when the {@link report} method is called.
|
7
|
+
*/
|
8
|
+
export type Exporter = (trace: {
|
9
|
+
resource: Context;
|
10
|
+
scopeSpans: IterableIterator<ScopedSpans>;
|
11
|
+
}) => any;
|
12
|
+
|
13
|
+
export type ScopedSpans = {
|
14
|
+
readonly scope: { readonly name: string };
|
15
|
+
readonly spans: ReadonlyArray<Readonly<Span>>;
|
16
|
+
};
|
17
|
+
|
18
|
+
export type Options = {
|
19
|
+
/**
|
20
|
+
* @borrows {@link Sampler}
|
21
|
+
*/
|
22
|
+
sampler?: Sampler | boolean;
|
23
|
+
|
24
|
+
/**
|
25
|
+
* A root, or extracted w3c traceparent string header.
|
26
|
+
*
|
27
|
+
* If the id is malformed, the {@link create} method will throw an exception. If no root is
|
28
|
+
* provided then one will be created obeying the {@link Options.sampler|sampling} rules on each span.
|
29
|
+
*/
|
30
|
+
traceparent?: string | null;
|
31
|
+
|
32
|
+
clock?: ClockLike;
|
33
|
+
};
|
34
|
+
|
35
|
+
export type Tracer = Pick<Scope, 'span'>;
|
36
|
+
|
37
|
+
/**
|
38
|
+
* @borrows {@link Span.context}
|
39
|
+
*/
|
40
|
+
export type Context = {
|
41
|
+
[property: string]: any;
|
42
|
+
};
|
43
|
+
|
44
|
+
/**
|
45
|
+
* Allows a sampling decision to be made. This method will influence the {@link Span.id|traceparent} sampling flag.
|
46
|
+
*
|
47
|
+
* Return true if the span should be sampled, and reported to the {@link Exporter}.
|
48
|
+
* Return false if the span should not be sampled, and not reported to the {@link Exporter}.
|
49
|
+
*/
|
50
|
+
export type Sampler = (
|
51
|
+
/**
|
52
|
+
* The name of the span.
|
53
|
+
*/
|
54
|
+
readonly name: string,
|
55
|
+
/**
|
56
|
+
* The traceparent id of the span.
|
57
|
+
*/
|
58
|
+
readonly id: Traceparent,
|
59
|
+
/**
|
60
|
+
* The tracer this span belongs to.
|
61
|
+
*/
|
62
|
+
readonly tracer: { readonly name: string },
|
63
|
+
) => boolean;
|
64
|
+
|
65
|
+
// --- spans
|
66
|
+
|
3
67
|
/**
|
4
68
|
* Spans are units within a distributed trace. Spans encapsulate mainly 3 pieces of information, a
|
5
69
|
* {@link Span.name|name}, and a {@link Span.start|start} and {@link Span.end|end} time.
|
6
70
|
*
|
7
71
|
* Each span should be named, not too vague, and not too precise. For example, "resolve_user_ids"
|
8
|
-
* and not "resolver_user_ids[1,2,3]" nor "
|
72
|
+
* and not "resolver_user_ids[1,2,3]" nor "resolver".
|
9
73
|
*
|
10
74
|
* A span forms part of a wider trace, and can be visualized like:
|
11
75
|
*
|
12
76
|
* ```plain
|
13
77
|
* [Span A················································(2ms)]
|
14
78
|
* [Span B·········································(1.7ms)]
|
15
|
-
* [Span D···············(0.8ms)]
|
79
|
+
* [Span D···············(0.8ms)] [Span C......(0.6ms)]
|
16
80
|
* ```
|
17
|
-
*
|
18
|
-
* ---
|
19
|
-
*
|
20
|
-
* Spans are aimed to interoperate with
|
21
|
-
* {@link https://github.com/opentracing/specification/blob/master/specification.md|OpenTracing's Spans}, albeit not entirely api compatible — they do share principles.
|
22
81
|
*/
|
23
|
-
export
|
82
|
+
export type Span = {
|
24
83
|
/**
|
25
84
|
* A human-readable name for this span. For example the function name, the name of a subtask,
|
26
85
|
* or stage of the larger stack.
|
27
86
|
*
|
28
87
|
* @example
|
88
|
+
*
|
29
89
|
* "resolve_user_ids"
|
30
90
|
* "[POST] /api"
|
31
91
|
*/
|
@@ -49,7 +109,7 @@ export interface Span {
|
|
49
109
|
/**
|
50
110
|
* The time represented as a UNIX epoch timestamp in milliseconds when this span was created.
|
51
111
|
* Typically, via
|
52
|
-
* {@link Scope.
|
112
|
+
* {@link Scope.span|scope.span()}.
|
53
113
|
*/
|
54
114
|
start: number;
|
55
115
|
|
@@ -63,7 +123,7 @@ export interface Span {
|
|
63
123
|
* An arbitrary context object useful for storing information during a trace.
|
64
124
|
*
|
65
125
|
* Usually following a convention such as `tag.*`, `http.*` or any of the
|
66
|
-
* {@link https://
|
126
|
+
* {@link https://opentelemetry.io/docs/reference/specification/trace/semantic_conventions/|OpenTelemetry Trace Semantic Conventions}.
|
67
127
|
*
|
68
128
|
* ### Note!
|
69
129
|
*
|
@@ -84,9 +144,11 @@ export interface Span {
|
|
84
144
|
* new span.
|
85
145
|
*/
|
86
146
|
events: { name: string; timestamp: number; attributes: Context }[];
|
87
|
-
}
|
147
|
+
};
|
88
148
|
|
89
|
-
|
149
|
+
// --- scopes
|
150
|
+
|
151
|
+
export type Scope = {
|
90
152
|
/**
|
91
153
|
* A W3C traceparent. One can .toString() this if you want to cross a network.
|
92
154
|
*/
|
@@ -95,7 +157,12 @@ export interface Scope {
|
|
95
157
|
/**
|
96
158
|
* Forks the span into a new child span.
|
97
159
|
*/
|
98
|
-
span(
|
160
|
+
span(
|
161
|
+
/**
|
162
|
+
* @borrows {@link Span.name}
|
163
|
+
*/
|
164
|
+
name: string,
|
165
|
+
): CallableScope;
|
99
166
|
|
100
167
|
/**
|
101
168
|
* Allows the span's context to be set. Passing an object will be `Object.assign`ed into the
|
@@ -116,70 +183,67 @@ export interface Scope {
|
|
116
183
|
* timestamp nulled out — when the tracer ends.
|
117
184
|
*/
|
118
185
|
end(): void;
|
119
|
-
}
|
186
|
+
};
|
187
|
+
|
188
|
+
export type CallableScope = Scope & {
|
189
|
+
<Fn extends (scope: Omit<Scope, 'end'>) => any>(cb: Fn): ReturnType<Fn>;
|
190
|
+
};
|
120
191
|
|
121
|
-
|
122
|
-
report(): ReturnType<Exporter>;
|
123
|
-
}
|
192
|
+
// --- main api
|
124
193
|
|
125
194
|
/**
|
126
|
-
*
|
127
|
-
*
|
195
|
+
* A tracer is a logical unit in your application. This alleviates the need to pass around a tracer instance.
|
196
|
+
*
|
197
|
+
* All spans produced by a tracer will all collect into a single span collection that is given to {@link report}.
|
198
|
+
*
|
199
|
+
* @example
|
200
|
+
*
|
201
|
+
* ```ts
|
202
|
+
* // file: server.ts
|
203
|
+
* const trace = tracer('server');
|
204
|
+
*
|
205
|
+
* // file: orm.ts
|
206
|
+
* const trace = tracer('orm');
|
207
|
+
*
|
208
|
+
* // file: api.ts
|
209
|
+
* const trace = tracer('api');
|
210
|
+
* ```
|
128
211
|
*/
|
129
|
-
export
|
130
|
-
|
131
|
-
|
132
|
-
) => any;
|
212
|
+
export function tracer(name: string, options?: Options): Tracer;
|
213
|
+
|
214
|
+
// -- general api
|
133
215
|
|
134
216
|
/**
|
135
|
-
*
|
217
|
+
* Awaits all active promises, and then calls the {@link Options.exporter|exporter}. Passing all collected spans.
|
136
218
|
*/
|
137
|
-
export
|
138
|
-
|
139
|
-
|
219
|
+
export async function report<T extends Exporter>(
|
220
|
+
exporter: T,
|
221
|
+
): Promise<ReturnType<T>>;
|
140
222
|
|
141
223
|
/**
|
142
|
-
*
|
143
|
-
*
|
224
|
+
* Calling this method will set the resource attributes for this runtime. This is useful for things like:
|
225
|
+
* - setting the deployment environment of the application
|
226
|
+
* - setting the k8s namespace
|
227
|
+
* - ...
|
144
228
|
*
|
145
|
-
* The
|
146
|
-
* filtered out there.
|
229
|
+
* The `name` argument will set the `service.name` attribute. And is required.
|
147
230
|
*
|
148
|
-
*
|
231
|
+
* The fields can be whatever you want, but it is recommended to follow the {@link https://opentelemetry.io/docs/reference/specification/resource/semantic_conventions/|OpenTelemetry Resource Semantic Conventions}.
|
232
|
+
*
|
233
|
+
* @example
|
234
|
+
*
|
235
|
+
* ```ts
|
236
|
+
* configure('my-service', { 'deployment.environment': 'production', 'k8s.namespace.name': 'default' });
|
237
|
+
* ```
|
149
238
|
*/
|
150
|
-
export
|
151
|
-
name: string,
|
152
|
-
parentId?: Traceparent,
|
153
|
-
context?: Context,
|
154
|
-
) => boolean;
|
155
|
-
|
156
|
-
export interface Options {
|
157
|
-
/**
|
158
|
-
* @borrows {@link Exporter}
|
159
|
-
*/
|
160
|
-
exporter: Exporter;
|
161
|
-
|
162
|
-
/**
|
163
|
-
* @borrows {@link Sampler}
|
164
|
-
*/
|
165
|
-
sampler?: Sampler | boolean;
|
166
|
-
|
167
|
-
context?: Context;
|
239
|
+
export function configure(name: string, attributes: Context = {}): void;
|
168
240
|
|
241
|
+
/**
|
242
|
+
* Provinding a clock allows you to control the time of the span.
|
243
|
+
*/
|
244
|
+
export type ClockLike = {
|
169
245
|
/**
|
170
|
-
*
|
171
|
-
*
|
172
|
-
* If the id is malformed, the {@link create} method will throw an exception. If no root is
|
173
|
-
* provided then one will be created obeying the {@link Options.sampler|sampling} rules.
|
246
|
+
* Must return the number of milliseconds since the epoch.
|
174
247
|
*/
|
175
|
-
|
176
|
-
}
|
177
|
-
|
178
|
-
export const create: (name: string, options: Options) => Tracer;
|
179
|
-
|
180
|
-
// ==> internals
|
181
|
-
|
182
|
-
/** @internal */
|
183
|
-
export interface CallableScope extends Scope {
|
184
|
-
(cb: (scope: Omit<Scope, 'end'>) => void): ReturnType<typeof cb>;
|
185
|
-
}
|
248
|
+
now(): number;
|
249
|
+
};
|
package/index.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
const {
|
1
|
+
const { measure:e } = require('rian/utils');const { make:t, parse:n, SAMPLED_FLAG:a } = require('tctx');const { is_sampled:r } = require('tctx');var o={};function s(e,t={}){o={...t,"service.name":e,"telemetry.sdk.name":"rian","telemetry.sdk.version":"0.3.0-next.11"}}var p=new Set,c=new WeakMap;async function i(e){let t=[],n=new Map;for(let[e,a]of p){let r;n.has(a)?r=n.get(a).spans:n.set(a,{scope:a,spans:r=[]}),r.push(e),c.has(a)&&(t.push(...c.get(a)),c.delete(a))}return p.clear(),t.length&&await Promise.all(t),e({resource:o,scopeSpans:n.values()})}function l(e,t){return r(t)}function d(a,r){let o=r?.sampler??l,s=r?.clock??Date,i={name:a},d=new Set;c.set(i,d);let m="string"==typeof r?.traceparent?n(r.traceparent):void 0,u=(n,a)=>{let r=a?a.child():t(),c="boolean"!=typeof o?o(n,r,i):o;r.flags;let l={id:r,parent:a,start:s.now(),name:n,events:[],context:{}};c&&p.add([l,i]);let m=t=>e(m,t);return m.traceparent=r,m.span=e=>u(e,r),m.set_context=e=>"function"==typeof e?void(l.context=e(l.context)):void Object.assign(l.context,e),m.add_event=(e,t)=>{l.events.push({name:e,timestamp:s.now(),attributes:t||{}})},m.end=()=>{null==l.end&&(l.end=s.now())},m.__add_promise=e=>{d.add(e),e.then((()=>d.delete(e)))},m};return{span:e=>u(e,m)}}exports.configure=s;exports.report=i;exports.tracer=d;
|
package/index.mjs
CHANGED
@@ -1 +1 @@
|
|
1
|
-
import{
|
1
|
+
import{measure as e}from"rian/utils";import{make as t,parse as n,SAMPLED_FLAG as a}from"tctx";import{is_sampled as r}from"tctx";var o={};function s(e,t={}){o={...t,"service.name":e,"telemetry.sdk.name":"rian","telemetry.sdk.version":"0.3.0-next.11"}}var p=new Set,c=new WeakMap;async function i(e){let t=[],n=new Map;for(let[e,a]of p){let r;n.has(a)?r=n.get(a).spans:n.set(a,{scope:a,spans:r=[]}),r.push(e),c.has(a)&&(t.push(...c.get(a)),c.delete(a))}return p.clear(),t.length&&await Promise.all(t),e({resource:o,scopeSpans:n.values()})}function l(e,t){return r(t)}function d(a,r){let o=r?.sampler??l,s=r?.clock??Date,i={name:a},d=new Set;c.set(i,d);let m="string"==typeof r?.traceparent?n(r.traceparent):void 0,u=(n,a)=>{let r=a?a.child():t(),c="boolean"!=typeof o?o(n,r,i):o;r.flags;let l={id:r,parent:a,start:s.now(),name:n,events:[],context:{}};c&&p.add([l,i]);let m=t=>e(m,t);return m.traceparent=r,m.span=e=>u(e,r),m.set_context=e=>"function"==typeof e?void(l.context=e(l.context)):void Object.assign(l.context,e),m.add_event=(e,t)=>{l.events.push({name:e,timestamp:s.now(),attributes:t||{}})},m.end=()=>{null==l.end&&(l.end=s.now())},m.__add_promise=e=>{d.add(e),e.then((()=>d.delete(e)))},m};return{span:e=>u(e,m)}}export{s as configure,i as report,d as tracer};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "rian",
|
3
|
-
"version": "0.3.0-next.
|
3
|
+
"version": "0.3.0-next.11",
|
4
4
|
"description": "Effective tracing for the edge and origins",
|
5
5
|
"keywords": [
|
6
6
|
"opentelemetry",
|
@@ -25,20 +25,25 @@
|
|
25
25
|
"import": "./index.mjs",
|
26
26
|
"require": "./index.js"
|
27
27
|
},
|
28
|
+
"./async": {
|
29
|
+
"types": "./async.d.ts",
|
30
|
+
"import": "./async.mjs",
|
31
|
+
"require": "./async.js"
|
32
|
+
},
|
28
33
|
"./exporter.otel.http": {
|
29
|
-
"types": "./exporter.otel.http
|
30
|
-
"import": "./exporter.otel.http
|
31
|
-
"require": "./exporter.otel.http
|
34
|
+
"types": "./exporter.otel.http.d.ts",
|
35
|
+
"import": "./exporter.otel.http.mjs",
|
36
|
+
"require": "./exporter.otel.http.js"
|
32
37
|
},
|
33
38
|
"./exporter.zipkin": {
|
34
|
-
"types": "./exporter.zipkin
|
35
|
-
"import": "./exporter.zipkin
|
36
|
-
"require": "./exporter.zipkin
|
39
|
+
"types": "./exporter.zipkin.d.ts",
|
40
|
+
"import": "./exporter.zipkin.mjs",
|
41
|
+
"require": "./exporter.zipkin.js"
|
37
42
|
},
|
38
43
|
"./utils": {
|
39
|
-
"types": "./utils
|
40
|
-
"import": "./utils
|
41
|
-
"require": "./utils
|
44
|
+
"types": "./utils.d.ts",
|
45
|
+
"import": "./utils.mjs",
|
46
|
+
"require": "./utils.js"
|
42
47
|
},
|
43
48
|
"./package.json": "./package.json"
|
44
49
|
},
|
@@ -49,6 +54,7 @@
|
|
49
54
|
"*.mjs",
|
50
55
|
"*.js",
|
51
56
|
"*.d.ts",
|
57
|
+
"!global.d.ts",
|
52
58
|
"exporter.*/*",
|
53
59
|
"utils/*"
|
54
60
|
],
|
package/readme.md
CHANGED
@@ -6,9 +6,6 @@
|
|
6
6
|
|
7
7
|
<p><code>npm add rian</code> doesn't overcomplicate tracing</p>
|
8
8
|
<span>
|
9
|
-
<a href="https://github.com/maraisr/rian/actions/workflows/ci.yml">
|
10
|
-
<img src="https://github.com/maraisr/rian/actions/workflows/ci.yml/badge.svg"/>
|
11
|
-
</a>
|
12
9
|
<a href="https://npm-stat.com/charts.html?package=rian">
|
13
10
|
<img src="https://badgen.net/npm/dw/rian?labelColor=black&color=black&cache=600" alt="downloads"/>
|
14
11
|
</a>
|
@@ -26,80 +23,136 @@
|
|
26
23
|
|
27
24
|
## ⚡ Features
|
28
25
|
|
29
|
-
- 🤔 **Familiar** — looks very much like
|
26
|
+
- 🤔 **Familiar** — looks very much like opentelemetry.
|
30
27
|
|
31
|
-
- ✅ **Simple** — `
|
28
|
+
- ✅ **Simple** — `configure()` an environment, create a `tracer()`, `report()` and done.
|
32
29
|
|
33
30
|
- 🏎 **Performant** — check the [benchmarks](#-benchmark).
|
34
31
|
|
35
|
-
- 🪶 **Lightweight** — a mere
|
32
|
+
- 🪶 **Lightweight** — a mere 1KB and next to no [dependencies](https://npm.anvaka.com/#/view/2d/rian/).
|
36
33
|
|
37
34
|
## 🚀 Usage
|
38
35
|
|
39
|
-
> Visit [/examples](/examples) for more
|
36
|
+
> Visit [/examples](/examples) for more!
|
40
37
|
|
41
38
|
```ts
|
42
|
-
import {
|
43
|
-
import { measure } from 'rian/utils';
|
39
|
+
import { configure, tracer, report } from 'rian';
|
44
40
|
import { exporter } from 'rian/exporter.otel.http';
|
45
41
|
|
46
|
-
// ~>
|
47
|
-
|
48
|
-
|
49
|
-
method: 'POST',
|
50
|
-
body: JSON.stringify(payload),
|
51
|
-
}),
|
52
|
-
);
|
53
|
-
|
54
|
-
// ~> Create a tracer — typically "per request" or "per operation"
|
55
|
-
const tracer = create('my-service', {
|
56
|
-
exporter: otel_endpoint,
|
42
|
+
// ~> configure the environment, all tracers will inherit this
|
43
|
+
configure('my-service' {
|
44
|
+
'service.version': 'DEV'
|
57
45
|
});
|
58
46
|
|
59
|
-
//
|
47
|
+
// ~> create a tracer — typically "per request" or "per operation".
|
48
|
+
const trace = tracer('request');
|
60
49
|
|
61
|
-
|
50
|
+
function handler(req) {
|
51
|
+
// ~> start a span
|
52
|
+
return trace.span(`${req.method} ${req.path}`)(async (s) => {
|
53
|
+
// set some fields on this span's context
|
54
|
+
s.set_context({ user_id: req.params.user_id });
|
62
55
|
|
63
|
-
|
64
|
-
|
65
|
-
});
|
56
|
+
// ~> span again for `db::read`
|
57
|
+
const data = await s.span('db::read')(() => db_execute('SELECT * FROM users'));
|
66
58
|
|
67
|
-
// ~>
|
68
|
-
const
|
59
|
+
// ~> maybe have some manual spanning
|
60
|
+
const processing_span = s.span('process records');
|
69
61
|
|
70
|
-
|
71
|
-
|
62
|
+
for (let row of data) {
|
63
|
+
processing_span.add_event('doing stuff', { id: row.id });
|
64
|
+
do_stuff(row);
|
65
|
+
}
|
72
66
|
|
73
|
-
|
74
|
-
|
75
|
-
do_stuff(row);
|
76
|
-
}
|
67
|
+
// don't forget to end
|
68
|
+
processing_span.end();
|
77
69
|
|
78
|
-
|
70
|
+
return reply(200, { data });
|
71
|
+
});
|
72
|
+
}
|
79
73
|
|
80
|
-
|
74
|
+
const otel_exporter = exporter((payload) =>
|
75
|
+
fetch('/traces/otlp', {
|
76
|
+
method: 'POST',
|
77
|
+
body: JSON.stringify(payload),
|
78
|
+
}),
|
79
|
+
);
|
81
80
|
|
82
|
-
|
83
|
-
|
81
|
+
http.listen((req, executionCtx) => {
|
82
|
+
// ~> report all the spans once the response is sent
|
83
|
+
executionCtx.defer(() => report(otel_exporter));
|
84
|
+
return handler(req);
|
85
|
+
});
|
84
86
|
|
85
87
|
/*
|
86
88
|
And we end up with something like this in our reporting tool:
|
87
89
|
|
88
|
-
[ GET
|
89
|
-
[ db::read .... (0.5ms) ]
|
90
|
-
|
90
|
+
[ GET /data .................,,...................... (1.2ms) ] { request }
|
91
|
+
[ db::read .... (0.5ms) ] [ process records .... (0.5ms) ]
|
92
|
+
^ ^ ^ ^
|
93
|
+
{ user_id } ev { id: 1 } | |
|
94
|
+
ev { id: 2 } |
|
95
|
+
ev { id: 3 }
|
91
96
|
*/
|
92
97
|
```
|
93
98
|
|
99
|
+
You only need to `report` in your application once somewhere. All spans are collected into the same "bucket".
|
100
|
+
|
94
101
|
## 🔎 API
|
95
102
|
|
96
103
|
#### Module: [`rian`](./packages/rian/src/index.ts)
|
97
104
|
|
98
105
|
The main and _default_ module responsible for creating and provisioning spans.
|
99
106
|
|
100
|
-
> 💡 Note ~> when providing span context values,
|
101
|
-
> [Semantic Conventions](https://
|
102
|
-
> enforced.
|
107
|
+
> 💡 Note ~> when providing span context values, you can use
|
108
|
+
> [Semantic Conventions](https://opentelemetry.io/docs/reference/specification/trace/semantic_conventions/), but won't
|
109
|
+
> be enforced.
|
110
|
+
|
111
|
+
#### Module: [`rian/async`](./packages/rian/src/async.ts)
|
112
|
+
|
113
|
+
A module that utilizes the `async_hooks` API to provide a `tracer` and `spans` that can be used where the current span
|
114
|
+
isn't accessible.
|
115
|
+
|
116
|
+
> 💡 Note ~> this module should be used mutually exclusively with the main `rian` module.
|
117
|
+
|
118
|
+
<detials>
|
119
|
+
|
120
|
+
<summary>Example</summary>
|
121
|
+
|
122
|
+
```ts
|
123
|
+
import { configure, tracer, span, currentSpan, report } from 'rian/async';
|
124
|
+
import { exporter } from 'rian/exporter.otel.http';
|
125
|
+
|
126
|
+
function handler(req) {
|
127
|
+
return span(`${req.method} ${req.path}`)(async () => {
|
128
|
+
const s = currentSpan();
|
129
|
+
|
130
|
+
s.set_context({ user_id: req.params.user_id });
|
131
|
+
|
132
|
+
const data = await s.span('db::read')(() => db_execute('SELECT * FROM users'));
|
133
|
+
|
134
|
+
const processing_span = s.span('process records');
|
135
|
+
|
136
|
+
for (let row of data) {
|
137
|
+
processing_span.add_event('doing stuff', { id: row.id });
|
138
|
+
do_stuff(row);
|
139
|
+
}
|
140
|
+
|
141
|
+
processing_span.end();
|
142
|
+
|
143
|
+
return reply(200, { data });
|
144
|
+
});
|
145
|
+
}
|
146
|
+
|
147
|
+
const httpTrace = tracer('http');
|
148
|
+
|
149
|
+
http.listen((req, executionCtx) => {
|
150
|
+
executionCtx.defer(() => report(exporter));
|
151
|
+
return httpTrace(() => handler(req));
|
152
|
+
});
|
153
|
+
```
|
154
|
+
|
155
|
+
</details>
|
103
156
|
|
104
157
|
#### Module: [`rian/exporter.zipkin`](./packages/rian/src/exporter.zipkin.ts)
|
105
158
|
|
@@ -114,7 +167,7 @@ Implements the OpenTelemetry protocol for use with http transports.
|
|
114
167
|
<details><summary>NewRelic</summary>
|
115
168
|
|
116
169
|
```ts
|
117
|
-
import {
|
170
|
+
import { configure, tracer, report } from 'rian';
|
118
171
|
import { exporter } from 'rian/exporter.zipkin';
|
119
172
|
|
120
173
|
const newrelic = exporter((payload) =>
|
@@ -130,23 +183,25 @@ const newrelic = exporter((payload) =>
|
|
130
183
|
}),
|
131
184
|
);
|
132
185
|
|
133
|
-
|
134
|
-
|
135
|
-
|
186
|
+
configure('my-service');
|
187
|
+
|
188
|
+
const tracer = tracer('app');
|
189
|
+
|
190
|
+
await report(newrelic);
|
136
191
|
```
|
137
192
|
|
138
193
|
[learn more](https://docs.newrelic.com/docs/distributed-tracing/trace-api/introduction-trace-api/)
|
139
194
|
|
140
195
|
</details>
|
141
196
|
|
142
|
-
<details><summary>
|
197
|
+
<details><summary>Lightstep</summary>
|
143
198
|
|
144
199
|
```ts
|
145
|
-
import {
|
200
|
+
import { configure, tracer, report } from 'rian';
|
146
201
|
import { exporter } from 'rian/exporter.otel.http';
|
147
202
|
|
148
203
|
const lightstep = exporter((payload) =>
|
149
|
-
fetch('https://ingest.lightstep.com/traces/otlp/v0.
|
204
|
+
fetch('https://ingest.lightstep.com/traces/otlp/v0.9', {
|
150
205
|
method: 'POST',
|
151
206
|
headers: {
|
152
207
|
'lightstep-access-token': '<your api key>',
|
@@ -156,9 +211,11 @@ const lightstep = exporter((payload) =>
|
|
156
211
|
}),
|
157
212
|
);
|
158
213
|
|
159
|
-
|
160
|
-
|
161
|
-
|
214
|
+
configure('my-service');
|
215
|
+
|
216
|
+
const tracer = tracer('app');
|
217
|
+
|
218
|
+
await report(lightstep);
|
162
219
|
```
|
163
220
|
|
164
221
|
[learn more](https://opentelemetry.lightstep.com/tracing/)
|
@@ -167,34 +224,23 @@ const tracer = create('my-service', {
|
|
167
224
|
|
168
225
|
## 🤔 Motivation
|
169
226
|
|
170
|
-
|
171
|
-
|
172
|
-
In efforts to be better observant citizens, we generally reach for the — NewRelic, LightStep, DataDog's. Which, and in
|
173
|
-
no offence to them, is bloated and slow! Where they more often than not do way too much or and relatively speaking, ship
|
174
|
-
useless traces. Which ramp up your bill — see... every span you trace, costs.
|
175
|
-
|
176
|
-
And here we are, introducing **rian** — a lightweight, fast effective tracer. Inspired by the giants in the industry,
|
177
|
-
OpenTracing and OpenTelemetry.
|
178
|
-
|
179
|
-
You might have not heard of those before — and that is okay. It means the design goals from OpenTelemetry or OpenTracing
|
180
|
-
has been met. They are frameworks built to abstract the telemetry part from vendors. So folk like NewRelic can wrap
|
181
|
-
their layers on top of open telemetry — and have libraries instrument theirs without knowing about the vendor. Which
|
182
|
-
allows consumers to ship those spans to the vendor of their choosing. OpenTracing has a very similar design goal, so
|
183
|
-
please do go checkout their documentation's, to help decide.
|
227
|
+
To clarify, `rian` is the Irish word for "trace".
|
184
228
|
|
185
|
-
|
186
|
-
|
187
|
-
MongoDB ran", or how many network calls your ORM made. Cardinality will destroy you. Although rian can scale to support
|
188
|
-
those as well. But the reality is; there are profiler tools far more capable — "right tool for the job".
|
229
|
+
In our efforts to be observant citizens, we often rely on tools such as NewRelic, Lightstep, and Datadog. However, these
|
230
|
+
tools can be bloated and slow, often performing too many unnecessary tasks and driving up costs, as every span costs.
|
189
231
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
have that forwarded onto all sub-services.
|
232
|
+
This is where rian comes in as a lightweight, fast, and effective tracer inspired by industry giants OpenTracing and
|
233
|
+
OpenTelemetry. These frameworks were designed to abstract the telemetry part from vendors, allowing libraries to be
|
234
|
+
instrumented without needing to know about the vendor.
|
194
235
|
|
195
|
-
|
236
|
+
Rian does not intend to align or compete with them, slightly different goals. Rian aims to be used exclusively for
|
237
|
+
instrumenting your application, particularly critical business paths. While rian can scale to support more complex
|
238
|
+
constructs, there are profiler tools that are better suited for those jobs. Rian's primary design goal is to provide
|
239
|
+
better insights into your application's behavior, particularly for edge or service workers where a lean tracer is
|
240
|
+
favored.
|
196
241
|
|
197
|
-
Rian
|
242
|
+
Rian does not by design handle injecting [`w3c trace-context`](https://www.w3.org/TR/trace-context/), or
|
243
|
+
[propagating baggage](https://www.w3.org/TR/baggage/). But we do expose api's for achieving this.
|
198
244
|
|
199
245
|
## 💨 Benchmark
|
200
246
|
|
@@ -204,22 +250,18 @@ Rian is still in active development, but ready for production!
|
|
204
250
|
Validation :: single span
|
205
251
|
✔ rian
|
206
252
|
✔ opentelemetry
|
207
|
-
✔ opentracing
|
208
253
|
|
209
254
|
Benchmark :: single span
|
210
|
-
rian x
|
211
|
-
opentelemetry x
|
212
|
-
opentracing x 60,043 ops/sec ±35.25% (97 runs sampled)
|
255
|
+
rian x 339,110 ops/sec ±2.11% (89 runs sampled)
|
256
|
+
opentelemetry x 199,246 ops/sec ±14.78% (67 runs sampled)
|
213
257
|
|
214
258
|
Validation :: child span
|
215
259
|
✔ rian
|
216
260
|
✔ opentelemetry
|
217
|
-
✔ opentracing
|
218
261
|
|
219
262
|
Benchmark :: child span
|
220
|
-
rian x
|
221
|
-
opentelemetry x
|
222
|
-
opentracing x 37,405 ops/sec ±0.48% (99 runs sampled)
|
263
|
+
rian x 176,936 ops/sec ±2.30% (88 runs sampled)
|
264
|
+
opentelemetry x 124,447 ops/sec ±13.72% (70 runs sampled)
|
223
265
|
```
|
224
266
|
|
225
267
|
> And please... I know these results are anything but the full story. But it's a number and point on comparison.
|
@@ -231,5 +273,5 @@ MIT © [Marais Rossouw](https://marais.io)
|
|
231
273
|
##### Disclaimer
|
232
274
|
|
233
275
|
<sup>- NewRelic is a registered trademark of https://newrelic.com/ and not affiliated with this project.</sup><br />
|
234
|
-
<sup>-
|
235
|
-
<sup>-
|
276
|
+
<sup>- Datadog is a registered trademark of https://www.datadoghq.com/ and not affiliated with this project.</sup><br />
|
277
|
+
<sup>- Lightstep is a registered trademark of https://lightstep.com/ and not affiliated with this project.</sup>
|
package/utils.d.ts
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
import type { Scope } from 'rian';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* With a passed function, `measure` will run the function and once finishes, will end the span.
|
5
|
+
*
|
6
|
+
* The measure method will return whatever the function is, so if it's a promise, it returns a
|
7
|
+
* promise and so on. Any error is caught and re thrown, and automatically tracked in the
|
8
|
+
* context under the `error` property.
|
9
|
+
*
|
10
|
+
* All promises are tracked, and awaited on a `report`.
|
11
|
+
*
|
12
|
+
* This is a utility method, but is functionally equivalent to `scope.span('name')(fn)`.
|
13
|
+
*
|
14
|
+
* @example
|
15
|
+
*
|
16
|
+
* ```text
|
17
|
+
* const data = await measure(scope, get_data);
|
18
|
+
* // or with arguments:
|
19
|
+
* const data = await measure(scope, () => get_data('foo', 'bar'));
|
20
|
+
* ```
|
21
|
+
*/
|
22
|
+
export function measure<Fn extends (scope: Scope) => any>(
|
23
|
+
scope: Scope,
|
24
|
+
fn: Fn,
|
25
|
+
): ReturnType<Fn>;
|
package/utils.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
function r(r,t){try{var e=t(r),n=e instanceof Promise;return n&&r.__add_promise(e.catch((t=>{r.set_context({error:t})})).finally((()=>r.end()))),e}catch(t){throw t instanceof Error&&r.set_context({error:t}),t}finally{!0!==n&&r.end()}}exports.measure=r;
|
package/utils.mjs
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
function r(r,t){try{var e=t(r),n=e instanceof Promise;return n&&r.__add_promise(e.catch((t=>{r.set_context({error:t})})).finally((()=>r.end()))),e}catch(t){throw t instanceof Error&&r.set_context({error:t}),t}finally{!0!==n&&r.end()}}export{r as measure};
|
@@ -1 +0,0 @@
|
|
1
|
-
var e=r=>{let n=typeof r,a={};return"string"===n?a.stringValue=r:"number"===n?Number.isInteger(r)?a.intValue=r:a.doubleValue=r:"boolean"===n?a.boolValue=r:Array.isArray(r)?a.arrayValue={values:r.map((t=>e(t)))}:r&&(a.kvlistValue={values:t(r)}),a},t=t=>{let r=[];for(let n of Object.keys(t))r.push({key:n,value:e(t[n])});return r},r=e=>{switch(e){default:case"INTERNAL":return 1;case"SERVER":return 2;case"CLIENT":return 3;case"PRODUCER":return 4;case"CONSUMER":return 5}},n=e=>(n,a)=>{let s=[];for(let e of n){let n,{kind:a,error:u,...i}=e.context;u&&(n={code:2},"message"in u&&(n.message=u.message)),s.push({traceId:e.id.trace_id,spanId:e.id.parent_id,parentSpanId:e.parent?.parent_id,name:e.name,kind:r(a||"INTERNAL"),startTimeUnixNano:1e6*e.start,endTimeUnixNano:e.end?1e6*e.end:void 0,droppedAttributesCount:0,droppedEventsCount:0,droppedLinksCount:0,attributes:t(i),status:n||{code:0},events:e.events.map((e=>({name:e.name,attributes:t(e.attributes),droppedAttributesCount:0,timeUnixNano:1e6*e.timestamp})))})}return e({resourceSpans:[{resource:{attributes:t(a),droppedAttributesCount:0},instrumentationLibrarySpans:[{instrumentationLibrary:{name:"rian",version:"0.3.0-next.1"},spans:s}]}]})};exports.exporter=n;
|
@@ -1 +0,0 @@
|
|
1
|
-
var e=r=>{let n=typeof r,a={};return"string"===n?a.stringValue=r:"number"===n?Number.isInteger(r)?a.intValue=r:a.doubleValue=r:"boolean"===n?a.boolValue=r:Array.isArray(r)?a.arrayValue={values:r.map((t=>e(t)))}:r&&(a.kvlistValue={values:t(r)}),a},t=t=>{let r=[];for(let n of Object.keys(t))r.push({key:n,value:e(t[n])});return r},r=e=>{switch(e){default:case"INTERNAL":return 1;case"SERVER":return 2;case"CLIENT":return 3;case"PRODUCER":return 4;case"CONSUMER":return 5}},n=e=>(n,a)=>{let s=[];for(let e of n){let n,{kind:a,error:u,...i}=e.context;u&&(n={code:2},"message"in u&&(n.message=u.message)),s.push({traceId:e.id.trace_id,spanId:e.id.parent_id,parentSpanId:e.parent?.parent_id,name:e.name,kind:r(a||"INTERNAL"),startTimeUnixNano:1e6*e.start,endTimeUnixNano:e.end?1e6*e.end:void 0,droppedAttributesCount:0,droppedEventsCount:0,droppedLinksCount:0,attributes:t(i),status:n||{code:0},events:e.events.map((e=>({name:e.name,attributes:t(e.attributes),droppedAttributesCount:0,timeUnixNano:1e6*e.timestamp})))})}return e({resourceSpans:[{resource:{attributes:t(a),droppedAttributesCount:0},instrumentationLibrarySpans:[{instrumentationLibrary:{name:"rian",version:"0.3.0-next.1"},spans:s}]}]})};export{n as exporter};
|
package/exporter.zipkin/index.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
const { flattie:e } = require('flattie');var t=t=>(a,r)=>{let n=[];for(let t of a){let{kind:a,error:i,...s}=t.context;i&&(s.error=!("message"in i)||{name:i.name,message:i.message,stack:i.stack}),n.push({id:t.id.parent_id,traceId:t.id.trace_id,parentId:t.parent?t.parent.parent_id:void 0,name:t.name,kind:"INTERNAL"===a?void 0:a,timestamp:1e3*t.start,duration:t.end?1e3*(t.end-t.start):void 0,localEndpoint:{serviceName:r["service.name"]},tags:e({...r,...s},".",!0),annotations:t.events.map((e=>({value:`${e.name} :: ${JSON.stringify(e.attributes)}`,timestamp:1e3*e.timestamp})))})}return t(n)};exports.exporter=t;
|
@@ -1 +0,0 @@
|
|
1
|
-
import{flattie as e}from"flattie";var t=t=>(a,r)=>{let n=[];for(let t of a){let{kind:a,error:i,...s}=t.context;i&&(s.error=!("message"in i)||{name:i.name,message:i.message,stack:i.stack}),n.push({id:t.id.parent_id,traceId:t.id.trace_id,parentId:t.parent?t.parent.parent_id:void 0,name:t.name,kind:"INTERNAL"===a?void 0:a,timestamp:1e3*t.start,duration:t.end?1e3*(t.end-t.start):void 0,localEndpoint:{serviceName:r["service.name"]},tags:e({...r,...s},".",!0),annotations:t.events.map((e=>({value:`${e.name} :: ${JSON.stringify(e.attributes)}`,timestamp:1e3*e.timestamp})))})}return t(n)};export{t as exporter};
|
package/utils/index.d.ts
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
import type { Scope } from 'rian';
|
2
|
-
|
3
|
-
export type MeasureFn =
|
4
|
-
| ((...args: [...args: any[]]) => any)
|
5
|
-
| ((...args: [...args: any[], scope: Scope]) => any);
|
6
|
-
|
7
|
-
/**
|
8
|
-
* With a passed function — will start a span, and run the function, when the function finishes
|
9
|
-
* the span finishes.
|
10
|
-
*
|
11
|
-
* The measure method will return whatever the function is, so if it's a promise, it returns a
|
12
|
-
* promise and so on. Any error is caught and re thrown, and automatically tracked in the
|
13
|
-
* context under the `error` property.
|
14
|
-
*
|
15
|
-
* All promises are tracked, and awaited on a `tracer.end`.
|
16
|
-
*
|
17
|
-
* @example
|
18
|
-
*
|
19
|
-
* ```text
|
20
|
-
* const data = await measure(scope, get_data, 'user_id_123');
|
21
|
-
* ^ ^ ^ ^
|
22
|
-
* | | | |
|
23
|
-
* | | | the first argument to get_data
|
24
|
-
* | | |
|
25
|
-
* | | function to be called
|
26
|
-
* | |
|
27
|
-
* | the parent scope
|
28
|
-
* return value from get_data
|
29
|
-
* ```
|
30
|
-
*/
|
31
|
-
export const measure: <Fn extends MeasureFn>(
|
32
|
-
scope: Scope,
|
33
|
-
fn: Fn, // TODO: fn doesnt see scope correctly
|
34
|
-
...args: RealMeasureFnParams<Parameters<Fn>>
|
35
|
-
) => ReturnType<Fn>;
|
36
|
-
|
37
|
-
/**
|
38
|
-
* Wraps any function with a measured scoped function. Useful for when defer function execution
|
39
|
-
* till a later time.
|
40
|
-
*
|
41
|
-
* @example
|
42
|
-
*
|
43
|
-
* ```js
|
44
|
-
* const wrapped = wrap(scope, "run something", my_function);
|
45
|
-
*
|
46
|
-
* // ... lots of things, where the access to `scope` is lost.
|
47
|
-
*
|
48
|
-
* wrapped();
|
49
|
-
* ```
|
50
|
-
*/
|
51
|
-
export const wrap: <Fn extends MeasureFn>(
|
52
|
-
scope: Scope,
|
53
|
-
fn: Fn, // TODO: fn doesnt see scope correctly
|
54
|
-
) => Fn;
|
55
|
-
|
56
|
-
// ==> internals
|
57
|
-
|
58
|
-
/** @internal */
|
59
|
-
export type RealMeasureFnParams<T extends unknown[]> = T extends []
|
60
|
-
? []
|
61
|
-
: T extends [...rest: infer U, scope: Scope]
|
62
|
-
? U
|
63
|
-
: T;
|
64
|
-
|
65
|
-
/** @internal */
|
66
|
-
export const measureFn: (scope: Scope, fn: any, ...args: any[]) => any;
|
package/utils/index.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
var r=(r,t,...e)=>{try{var n=t(...e,r),o=n instanceof Promise;return o&&r.__add_promise(n.catch((t=>{r.set_context({error:t})})).finally((()=>r.end()))),n}catch(t){throw t instanceof Error&&r.set_context({error:t}),t}finally{!0!==o&&r.end()}},t=(t,e,...n)=>r(t,e,...n),e=(t,e)=>function(){return r(t,e,...arguments)};exports.measure=t;exports.measureFn=r;exports.wrap=e;
|
package/utils/index.mjs
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
var r=(r,t,...e)=>{try{var n=t(...e,r),o=n instanceof Promise;return o&&r.__add_promise(n.catch((t=>{r.set_context({error:t})})).finally((()=>r.end()))),n}catch(t){throw t instanceof Error&&r.set_context({error:t}),t}finally{!0!==o&&r.end()}},t=(t,e,...n)=>r(t,e,...n),e=(t,e)=>function(){return r(t,e,...arguments)};export{t as measure,r as measureFn,e as wrap};
|
File without changes
|
File without changes
|