rian 0.3.0-next.9 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
package/index.d.ts CHANGED
@@ -3,8 +3,7 @@ import type { Traceparent } from 'tctx';
3
3
  // --- tracer
4
4
 
5
5
  /**
6
- * An exporter is a method called when the parent scope ends, gets given a Set of all spans traced
7
- * during this execution.
6
+ * The exporter is called when the {@link report} method is called.
8
7
  */
9
8
  export type Exporter = (trace: {
10
9
  resource: Context;
@@ -23,12 +22,14 @@ export type Options = {
23
22
  sampler?: Sampler | boolean;
24
23
 
25
24
  /**
26
- * A root, or extracted w3c traceparent stringed header.
25
+ * A root, or extracted w3c traceparent string header.
27
26
  *
28
27
  * If the id is malformed, the {@link create} method will throw an exception. If no root is
29
- * provided then one will be created obeying the {@link Options.sampler|sampling} rules.
28
+ * provided then one will be created obeying the {@link Options.sampler|sampling} rules on each span.
30
29
  */
31
30
  traceparent?: string | null;
31
+
32
+ clock?: ClockLike;
32
33
  };
33
34
 
34
35
  export type Tracer = Pick<Scope, 'span'>;
@@ -41,17 +42,24 @@ export type Context = {
41
42
  };
42
43
 
43
44
  /**
44
- * Should return true when you want to sample the span, this is ran before the span is traced — so
45
- * decisions is made preemptively.
46
- *
47
- * Returning false will not include this span in the {@link Exporter}.
45
+ * Allows a sampling decision to be made. This method will influence the {@link Span.id|traceparent} sampling flag.
48
46
  *
49
- * Sampling does impact the traceparent, for injection and is encoded there.
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}.
50
49
  */
51
50
  export type Sampler = (
51
+ /**
52
+ * The name of the span.
53
+ */
52
54
  readonly name: string,
55
+ /**
56
+ * The traceparent id of the span.
57
+ */
53
58
  readonly id: Traceparent,
54
- readonly scope: { readonly name: string },
59
+ /**
60
+ * The tracer this span belongs to.
61
+ */
62
+ readonly tracer: { readonly name: string },
55
63
  ) => boolean;
56
64
 
57
65
  // --- spans
@@ -61,20 +69,15 @@ export type Sampler = (
61
69
  * {@link Span.name|name}, and a {@link Span.start|start} and {@link Span.end|end} time.
62
70
  *
63
71
  * Each span should be named, not too vague, and not too precise. For example, "resolve_user_ids"
64
- * and not "resolver_user_ids[1,2,3]" nor "resolve".
72
+ * and not "resolver_user_ids[1,2,3]" nor "resolver".
65
73
  *
66
74
  * A span forms part of a wider trace, and can be visualized like:
67
75
  *
68
76
  * ```plain
69
77
  * [Span A················································(2ms)]
70
78
  * [Span B·········································(1.7ms)]
71
- * [Span D···············(0.8ms)] [Span C......(0.6ms)]
79
+ * [Span D···············(0.8ms)] [Span C......(0.6ms)]
72
80
  * ```
73
- *
74
- * ---
75
- *
76
- * Spans are aimed to interoperate with
77
- * {@link https://github.com/opentracing/specification/blob/master/specification.md|OpenTracing's Spans}, albeit not entirely api compatible — they do share principles.
78
81
  */
79
82
  export type Span = {
80
83
  /**
@@ -82,6 +85,7 @@ export type Span = {
82
85
  * or stage of the larger stack.
83
86
  *
84
87
  * @example
88
+ *
85
89
  * "resolve_user_ids"
86
90
  * "[POST] /api"
87
91
  */
@@ -105,7 +109,7 @@ export type Span = {
105
109
  /**
106
110
  * The time represented as a UNIX epoch timestamp in milliseconds when this span was created.
107
111
  * Typically, via
108
- * {@link Scope.fork|tracer.fork()}.
112
+ * {@link Scope.span|scope.span()}.
109
113
  */
110
114
  start: number;
111
115
 
@@ -119,7 +123,7 @@ export type Span = {
119
123
  * An arbitrary context object useful for storing information during a trace.
120
124
  *
121
125
  * Usually following a convention such as `tag.*`, `http.*` or any of the
122
- * {@link https://github.com/opentracing/specification/blob/master/semantic_conventions.md|Semantic Conventions outlined by OpenTracing}.
126
+ * {@link https://opentelemetry.io/docs/reference/specification/trace/semantic_conventions/|OpenTelemetry Trace Semantic Conventions}.
123
127
  *
124
128
  * ### Note!
125
129
  *
@@ -153,7 +157,12 @@ export type Scope = {
153
157
  /**
154
158
  * Forks the span into a new child span.
155
159
  */
156
- span(name: string): CallableScope;
160
+ span(
161
+ /**
162
+ * @borrows {@link Span.name}
163
+ */
164
+ name: string,
165
+ ): CallableScope;
157
166
 
158
167
  /**
159
168
  * Allows the span's context to be set. Passing an object will be `Object.assign`ed into the
@@ -177,13 +186,33 @@ export type Scope = {
177
186
  };
178
187
 
179
188
  export type CallableScope = Scope & {
180
- (cb: (scope: Omit<Scope, 'end'>) => void): ReturnType<typeof cb>;
189
+ <Fn extends (scope: Omit<Scope, 'end'>) => any>(cb: Fn): ReturnType<Fn>;
181
190
  };
182
191
 
183
192
  // --- main api
184
193
 
194
+ /**
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
+ * ```
211
+ */
185
212
  export function tracer(name: string, options?: Options): Tracer;
186
213
 
214
+ // -- general api
215
+
187
216
  /**
188
217
  * Awaits all active promises, and then calls the {@link Options.exporter|exporter}. Passing all collected spans.
189
218
  */
@@ -191,5 +220,30 @@ export async function report<T extends Exporter>(
191
220
  exporter: T,
192
221
  ): Promise<ReturnType<T>>;
193
222
 
194
- // TODO
223
+ /**
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
+ * - ...
228
+ *
229
+ * The `name` argument will set the `service.name` attribute. And is required.
230
+ *
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
+ * ```
238
+ */
195
239
  export function configure(name: string, attributes: Context = {}): void;
240
+
241
+ /**
242
+ * Provinding a clock allows you to control the time of the span.
243
+ */
244
+ export type ClockLike = {
245
+ /**
246
+ * Must return the number of milliseconds since the epoch.
247
+ */
248
+ now(): number;
249
+ };
package/index.js CHANGED
@@ -1,74 +1 @@
1
- // src/index.ts
2
- const { measureFn } = require('rian/utils');
3
- const { make, parse, SAMPLED_FLAG } = require('tctx');
4
-
5
- // src/_internal/index.ts
6
- const { is_sampled } = require('tctx');
7
- var resource = {};
8
- function configure(name, attributes = {}) {
9
- resource = {
10
- ...attributes,
11
- ["service.name"]: name,
12
- ["telemetry.sdk.name"]: "rian",
13
- ["telemetry.sdk.version"]: "0.3.0-next.9"
14
- };
15
- }
16
- var span_buffer = /* @__PURE__ */ new Set(), wait_promises = /* @__PURE__ */ new WeakMap();
17
- async function report(exporter) {
18
- let ps = [], scopes = /* @__PURE__ */ new Map();
19
- for (let [span, scope] of span_buffer) {
20
- let spans;
21
- scopes.has(scope) ? spans = scopes.get(scope).spans : scopes.set(scope, {
22
- scope,
23
- spans: spans = []
24
- }), spans.push(span), wait_promises.has(scope) && (ps.push(...wait_promises.get(scope)), wait_promises.delete(scope));
25
- }
26
- return span_buffer.clear(), ps.length && await Promise.all(ps), exporter({
27
- resource,
28
- scopeSpans: scopes.values()
29
- });
30
- }
31
- function defaultSampler(_name, id) {
32
- return is_sampled(id);
33
- }
34
-
35
- // src/index.ts
36
- function tracer(name, options) {
37
- let sampler = options?.sampler ?? defaultSampler, scope = { name }, ps = /* @__PURE__ */ new Set();
38
- wait_promises.set(scope, ps);
39
- let root_id = typeof options?.traceparent == "string" ? parse(options.traceparent) : void 0, span = (name2, parent) => {
40
- let id = parent ? parent.child() : make(), should_sample = typeof sampler != "boolean" ? sampler(name2, id, scope) : sampler;
41
- should_sample ? id.flags | SAMPLED_FLAG : id.flags & ~SAMPLED_FLAG;
42
- let span_obj = {
43
- id,
44
- parent,
45
- start: Date.now(),
46
- name: name2,
47
- events: [],
48
- context: {}
49
- };
50
- should_sample && span_buffer.add([span_obj, scope]);
51
- let $ = (cb) => measureFn($, cb);
52
- return $.traceparent = id, $.span = (name3) => span(name3, id), $.set_context = (ctx) => typeof ctx == "function" ? void (span_obj.context = ctx(span_obj.context)) : void Object.assign(span_obj.context, ctx), $.add_event = (name3, attributes) => {
53
- span_obj.events.push({
54
- name: name3,
55
- timestamp: Date.now(),
56
- attributes: attributes || {}
57
- });
58
- }, $.end = () => {
59
- span_obj.end == null && (span_obj.end = Date.now());
60
- }, $.__add_promise = (p) => {
61
- ps.add(p), p.then(() => ps.delete(p));
62
- }, $;
63
- };
64
- return {
65
- span(name2) {
66
- return span(name2, root_id);
67
- }
68
- };
69
- }
70
-
71
-
72
- exports.configure = configure;
73
- exports.report = report;
74
- exports.tracer = tracer;
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.1"}}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,74 +1 @@
1
- // src/index.ts
2
- import { measureFn } from "rian/utils";
3
- import { make, parse, SAMPLED_FLAG } from "tctx";
4
-
5
- // src/_internal/index.ts
6
- import { is_sampled } from "tctx";
7
- var resource = {};
8
- function configure(name, attributes = {}) {
9
- resource = {
10
- ...attributes,
11
- ["service.name"]: name,
12
- ["telemetry.sdk.name"]: "rian",
13
- ["telemetry.sdk.version"]: "0.3.0-next.9"
14
- };
15
- }
16
- var span_buffer = /* @__PURE__ */ new Set(), wait_promises = /* @__PURE__ */ new WeakMap();
17
- async function report(exporter) {
18
- let ps = [], scopes = /* @__PURE__ */ new Map();
19
- for (let [span, scope] of span_buffer) {
20
- let spans;
21
- scopes.has(scope) ? spans = scopes.get(scope).spans : scopes.set(scope, {
22
- scope,
23
- spans: spans = []
24
- }), spans.push(span), wait_promises.has(scope) && (ps.push(...wait_promises.get(scope)), wait_promises.delete(scope));
25
- }
26
- return span_buffer.clear(), ps.length && await Promise.all(ps), exporter({
27
- resource,
28
- scopeSpans: scopes.values()
29
- });
30
- }
31
- function defaultSampler(_name, id) {
32
- return is_sampled(id);
33
- }
34
-
35
- // src/index.ts
36
- function tracer(name, options) {
37
- let sampler = options?.sampler ?? defaultSampler, scope = { name }, ps = /* @__PURE__ */ new Set();
38
- wait_promises.set(scope, ps);
39
- let root_id = typeof options?.traceparent == "string" ? parse(options.traceparent) : void 0, span = (name2, parent) => {
40
- let id = parent ? parent.child() : make(), should_sample = typeof sampler != "boolean" ? sampler(name2, id, scope) : sampler;
41
- should_sample ? id.flags | SAMPLED_FLAG : id.flags & ~SAMPLED_FLAG;
42
- let span_obj = {
43
- id,
44
- parent,
45
- start: Date.now(),
46
- name: name2,
47
- events: [],
48
- context: {}
49
- };
50
- should_sample && span_buffer.add([span_obj, scope]);
51
- let $ = (cb) => measureFn($, cb);
52
- return $.traceparent = id, $.span = (name3) => span(name3, id), $.set_context = (ctx) => typeof ctx == "function" ? void (span_obj.context = ctx(span_obj.context)) : void Object.assign(span_obj.context, ctx), $.add_event = (name3, attributes) => {
53
- span_obj.events.push({
54
- name: name3,
55
- timestamp: Date.now(),
56
- attributes: attributes || {}
57
- });
58
- }, $.end = () => {
59
- span_obj.end == null && (span_obj.end = Date.now());
60
- }, $.__add_promise = (p) => {
61
- ps.add(p), p.then(() => ps.delete(p));
62
- }, $;
63
- };
64
- return {
65
- span(name2) {
66
- return span(name2, root_id);
67
- }
68
- };
69
- }
70
- export {
71
- configure,
72
- report,
73
- tracer
74
- };
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.1"}}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.9",
3
+ "version": "0.3.1",
4
4
  "description": "Effective tracing for the edge and origins",
5
5
  "keywords": [
6
6
  "opentelemetry",
@@ -60,7 +60,7 @@
60
60
  ],
61
61
  "scripts": {
62
62
  "bench": "node -r tsm bench/index.ts",
63
- "build": "bundt",
63
+ "build": "bundt --minify",
64
64
  "format": "prettier --write \"{*,{src,test}/**/*,examples/*/**,bench/*,.github/**/*}.+(ts|js|json|yml|md)\"",
65
65
  "pretest": "pnpm run build",
66
66
  "test": "uvu -r tsm test \".spec.m?ts$\"",