rian 0.3.0-next.9 → 0.3.1

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/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$\"",