rian 0.2.1 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,110 +1 @@
1
- // src/exporter.otel.http.ts
2
- const { name:rian_name, version:rian_version } = require('rian/package.json');
3
- var SpanStatusCode_UNSET = 0;
4
- var SpanStatusCode_ERROR = 2;
5
- var convert_value_to_anyvalue = (value) => {
6
- let type = typeof value, any_value = {};
7
- if (type === "string")
8
- any_value.stringValue = value;
9
- else if (type === "number")
10
- if (Number.isInteger(value))
11
- any_value.intValue = value;
12
- else
13
- any_value.doubleValue = value;
14
- else if (type === "boolean")
15
- any_value.boolValue = value;
16
- else if (Array.isArray(value))
17
- any_value.arrayValue = {
18
- values: value.map((i) => convert_value_to_anyvalue(i))
19
- };
20
- else if (value)
21
- any_value.kvlistValue = { values: convert_object_to_kv(value) };
22
- return any_value;
23
- };
24
- var convert_object_to_kv = (input) => {
25
- const value = [];
26
- for (let key of Object.keys(input)) {
27
- value.push({
28
- key,
29
- value: convert_value_to_anyvalue(input[key])
30
- });
31
- }
32
- return value;
33
- };
34
- var map_kind = (kind) => {
35
- switch (kind) {
36
- default:
37
- case "INTERNAL": {
38
- return 1;
39
- }
40
- case "SERVER": {
41
- return 2;
42
- }
43
- case "CLIENT": {
44
- return 3;
45
- }
46
- case "PRODUCER": {
47
- return 4;
48
- }
49
- case "CONSUMER": {
50
- return 5;
51
- }
52
- }
53
- };
54
- var exporter = (request) => (spans, context) => {
55
- const otel_spans = [];
56
- for (let span of spans) {
57
- const { kind, error, ...span_ctx } = span.context;
58
- let status;
59
- if (error) {
60
- status = {
61
- code: SpanStatusCode_ERROR
62
- };
63
- if ("message" in error) {
64
- status.message = error.message;
65
- }
66
- }
67
- otel_spans.push({
68
- traceId: span.id.trace_id,
69
- spanId: span.id.parent_id,
70
- parentSpanId: span.parent?.parent_id,
71
- name: span.name,
72
- kind: map_kind(kind || "INTERNAL"),
73
- startTimeUnixNano: span.start * 1e6,
74
- endTimeUnixNano: span.end ? span.end * 1e6 : void 0,
75
- droppedAttributesCount: 0,
76
- droppedEventsCount: 0,
77
- droppedLinksCount: 0,
78
- attributes: convert_object_to_kv(span_ctx),
79
- status: status || { code: SpanStatusCode_UNSET },
80
- events: span.events.map((i) => ({
81
- name: i.name,
82
- attributes: convert_object_to_kv(i.attributes),
83
- droppedAttributesCount: 0,
84
- timeUnixNano: i.timestamp * 1e6
85
- }))
86
- });
87
- }
88
- return request({
89
- resourceSpans: [
90
- {
91
- resource: {
92
- attributes: convert_object_to_kv(context),
93
- droppedAttributesCount: 0
94
- },
95
- instrumentationLibrarySpans: [
96
- {
97
- instrumentationLibrary: {
98
- name: rian_name,
99
- version: rian_version
100
- },
101
- spans: otel_spans
102
- }
103
- ]
104
- }
105
- ]
106
- });
107
- };
108
-
109
-
110
- exports.exporter = exporter;
1
+ const { name:e, version:t } = require('rian/package.json');var r=e=>{let t=typeof e,n={};return"string"===t?n.stringValue=e:"number"===t?Number.isInteger(e)?n.intValue=e:n.doubleValue=e:"boolean"===t?n.boolValue=e:Array.isArray(e)?n.arrayValue={values:e.map((e=>r(e)))}:e&&(n.kvlistValue={values:a(e)}),n},a=e=>{let t=[];for(let a of Object.keys(e))t.push({key:a,value:r(e[a])});return t},n=e=>{switch(e){default:case"INTERNAL":return 1;case"SERVER":return 2;case"CLIENT":return 3;case"PRODUCER":return 4;case"CONSUMER":return 5}},s=r=>(s,i)=>{let u=[];for(let e of s){let t,{kind:r,error:s,...i}=e.context;s&&(t={code:2},"message"in s&&(t.message=s.message)),u.push({traceId:e.id.trace_id,spanId:e.id.parent_id,parentSpanId:e.parent?.parent_id,name:e.name,kind:n(r||"INTERNAL"),startTimeUnixNano:1e6*e.start,endTimeUnixNano:e.end?1e6*e.end:void 0,droppedAttributesCount:0,droppedEventsCount:0,droppedLinksCount:0,attributes:a(i),status:t||{code:0},events:e.events.map((e=>({name:e.name,attributes:a(e.attributes),droppedAttributesCount:0,timeUnixNano:1e6*e.timestamp})))})}return r({resourceSpans:[{resource:{attributes:a(i),droppedAttributesCount:0},instrumentationLibrarySpans:[{instrumentationLibrary:{name:e,version:t},spans:u}]}]})};exports.exporter=s;
@@ -1,110 +1 @@
1
- // src/exporter.otel.http.ts
2
- import { name as rian_name, version as rian_version } from "rian/package.json";
3
- var SpanStatusCode_UNSET = 0;
4
- var SpanStatusCode_ERROR = 2;
5
- var convert_value_to_anyvalue = (value) => {
6
- let type = typeof value, any_value = {};
7
- if (type === "string")
8
- any_value.stringValue = value;
9
- else if (type === "number")
10
- if (Number.isInteger(value))
11
- any_value.intValue = value;
12
- else
13
- any_value.doubleValue = value;
14
- else if (type === "boolean")
15
- any_value.boolValue = value;
16
- else if (Array.isArray(value))
17
- any_value.arrayValue = {
18
- values: value.map((i) => convert_value_to_anyvalue(i))
19
- };
20
- else if (value)
21
- any_value.kvlistValue = { values: convert_object_to_kv(value) };
22
- return any_value;
23
- };
24
- var convert_object_to_kv = (input) => {
25
- const value = [];
26
- for (let key of Object.keys(input)) {
27
- value.push({
28
- key,
29
- value: convert_value_to_anyvalue(input[key])
30
- });
31
- }
32
- return value;
33
- };
34
- var map_kind = (kind) => {
35
- switch (kind) {
36
- default:
37
- case "INTERNAL": {
38
- return 1;
39
- }
40
- case "SERVER": {
41
- return 2;
42
- }
43
- case "CLIENT": {
44
- return 3;
45
- }
46
- case "PRODUCER": {
47
- return 4;
48
- }
49
- case "CONSUMER": {
50
- return 5;
51
- }
52
- }
53
- };
54
- var exporter = (request) => (spans, context) => {
55
- const otel_spans = [];
56
- for (let span of spans) {
57
- const { kind, error, ...span_ctx } = span.context;
58
- let status;
59
- if (error) {
60
- status = {
61
- code: SpanStatusCode_ERROR
62
- };
63
- if ("message" in error) {
64
- status.message = error.message;
65
- }
66
- }
67
- otel_spans.push({
68
- traceId: span.id.trace_id,
69
- spanId: span.id.parent_id,
70
- parentSpanId: span.parent?.parent_id,
71
- name: span.name,
72
- kind: map_kind(kind || "INTERNAL"),
73
- startTimeUnixNano: span.start * 1e6,
74
- endTimeUnixNano: span.end ? span.end * 1e6 : void 0,
75
- droppedAttributesCount: 0,
76
- droppedEventsCount: 0,
77
- droppedLinksCount: 0,
78
- attributes: convert_object_to_kv(span_ctx),
79
- status: status || { code: SpanStatusCode_UNSET },
80
- events: span.events.map((i) => ({
81
- name: i.name,
82
- attributes: convert_object_to_kv(i.attributes),
83
- droppedAttributesCount: 0,
84
- timeUnixNano: i.timestamp * 1e6
85
- }))
86
- });
87
- }
88
- return request({
89
- resourceSpans: [
90
- {
91
- resource: {
92
- attributes: convert_object_to_kv(context),
93
- droppedAttributesCount: 0
94
- },
95
- instrumentationLibrarySpans: [
96
- {
97
- instrumentationLibrary: {
98
- name: rian_name,
99
- version: rian_version
100
- },
101
- spans: otel_spans
102
- }
103
- ]
104
- }
105
- ]
106
- });
107
- };
108
- export {
109
- exporter
110
- };
1
+ import{name as e,version as t}from"rian/package.json";var r=e=>{let t=typeof e,n={};return"string"===t?n.stringValue=e:"number"===t?Number.isInteger(e)?n.intValue=e:n.doubleValue=e:"boolean"===t?n.boolValue=e:Array.isArray(e)?n.arrayValue={values:e.map((e=>r(e)))}:e&&(n.kvlistValue={values:a(e)}),n},a=e=>{let t=[];for(let a of Object.keys(e))t.push({key:a,value:r(e[a])});return t},n=e=>{switch(e){default:case"INTERNAL":return 1;case"SERVER":return 2;case"CLIENT":return 3;case"PRODUCER":return 4;case"CONSUMER":return 5}},s=r=>(s,i)=>{let u=[];for(let e of s){let t,{kind:r,error:s,...i}=e.context;s&&(t={code:2},"message"in s&&(t.message=s.message)),u.push({traceId:e.id.trace_id,spanId:e.id.parent_id,parentSpanId:e.parent?.parent_id,name:e.name,kind:n(r||"INTERNAL"),startTimeUnixNano:1e6*e.start,endTimeUnixNano:e.end?1e6*e.end:void 0,droppedAttributesCount:0,droppedEventsCount:0,droppedLinksCount:0,attributes:a(i),status:t||{code:0},events:e.events.map((e=>({name:e.name,attributes:a(e.attributes),droppedAttributesCount:0,timeUnixNano:1e6*e.timestamp})))})}return r({resourceSpans:[{resource:{attributes:a(i),droppedAttributesCount:0},instrumentationLibrarySpans:[{instrumentationLibrary:{name:e,version:t},spans:u}]}]})};export{s as exporter};
@@ -1,43 +1 @@
1
- // src/exporter.zipkin.ts
2
- const { flattie } = require('flattie');
3
- var exporter = (request) => (spans, context) => {
4
- const zipkin = [];
5
- for (let span of spans) {
6
- const { kind, error, ...span_ctx } = span.context;
7
- if (error) {
8
- if ("message" in error) {
9
- span_ctx.error = {
10
- name: error.name,
11
- message: error.message,
12
- stack: error.stack
13
- };
14
- } else {
15
- span_ctx.error = true;
16
- }
17
- }
18
- zipkin.push({
19
- id: span.id.parent_id,
20
- traceId: span.id.trace_id,
21
- parentId: span.parent ? span.parent.parent_id : void 0,
22
- name: span.name,
23
- kind: kind === "INTERNAL" ? void 0 : kind,
24
- timestamp: span.start * 1e3,
25
- duration: span.end ? (span.end - span.start) * 1e3 : void 0,
26
- localEndpoint: context.localEndpoint || {
27
- serviceName: span_ctx["service.name"]
28
- },
29
- tags: flattie({
30
- ...context,
31
- ...span_ctx
32
- }, ".", true),
33
- annotations: span.events.map((i) => ({
34
- value: `${i.name} :: ${JSON.stringify(i.attributes)}`,
35
- timestamp: i.timestamp * 1e3
36
- }))
37
- });
38
- }
39
- return request(zipkin);
40
- };
41
-
42
-
43
- exports.exporter = exporter;
1
+ const { flattie:e } = require('flattie');var t=t=>(a,n)=>{let r=[];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}),r.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:n.localEndpoint||{serviceName:s["service.name"]},tags:e({...n,...s},".",!0),annotations:t.events.map((e=>({value:`${e.name} :: ${JSON.stringify(e.attributes)}`,timestamp:1e3*e.timestamp})))})}return t(r)};exports.exporter=t;
@@ -1,43 +1 @@
1
- // src/exporter.zipkin.ts
2
- import { flattie } from "flattie";
3
- var exporter = (request) => (spans, context) => {
4
- const zipkin = [];
5
- for (let span of spans) {
6
- const { kind, error, ...span_ctx } = span.context;
7
- if (error) {
8
- if ("message" in error) {
9
- span_ctx.error = {
10
- name: error.name,
11
- message: error.message,
12
- stack: error.stack
13
- };
14
- } else {
15
- span_ctx.error = true;
16
- }
17
- }
18
- zipkin.push({
19
- id: span.id.parent_id,
20
- traceId: span.id.trace_id,
21
- parentId: span.parent ? span.parent.parent_id : void 0,
22
- name: span.name,
23
- kind: kind === "INTERNAL" ? void 0 : kind,
24
- timestamp: span.start * 1e3,
25
- duration: span.end ? (span.end - span.start) * 1e3 : void 0,
26
- localEndpoint: context.localEndpoint || {
27
- serviceName: span_ctx["service.name"]
28
- },
29
- tags: flattie({
30
- ...context,
31
- ...span_ctx
32
- }, ".", true),
33
- annotations: span.events.map((i) => ({
34
- value: `${i.name} :: ${JSON.stringify(i.attributes)}`,
35
- timestamp: i.timestamp * 1e3
36
- }))
37
- });
38
- }
39
- return request(zipkin);
40
- };
41
- export {
42
- exporter
43
- };
1
+ import{flattie as e}from"flattie";var t=t=>(a,n)=>{let r=[];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}),r.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:n.localEndpoint||{serviceName:s["service.name"]},tags:e({...n,...s},".",!0),annotations:t.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
@@ -170,7 +170,7 @@ export interface Options {
170
170
  * If the id is malformed, the {@link create} method will throw an exception. If no root is
171
171
  * provided then one will be created obeying the {@link Options.sampler|sampling} rules.
172
172
  */
173
- traceparent?: string;
173
+ traceparent?: string | null;
174
174
  }
175
175
 
176
176
  export const create: (name: string, options: Options) => Tracer;
@@ -181,9 +181,3 @@ export const create: (name: string, options: Options) => Tracer;
181
181
  export interface CallableScope extends Scope {
182
182
  (cb: (scope: Omit<Scope, 'end'>) => void): ReturnType<typeof cb>;
183
183
  }
184
-
185
- /** @internal */
186
- export const PROMISES: WeakMap<Scope, Promise<any>[]>;
187
-
188
- /** @internal */
189
- export const ADD_PROMISE: (scope: Scope, promise: Promise<any>) => void;
package/index.js CHANGED
@@ -1,76 +1 @@
1
- // src/index.ts
2
- const { name:rian_name, version:rian_version } = require('rian/package.json');
3
- const tctx = require('tctx');
4
- const { measureFn } = require('rian/utils');
5
- var PROMISES = /* @__PURE__ */ new WeakMap();
6
- var ADD_PROMISE = (scope, promise) => {
7
- if (PROMISES.has(scope))
8
- PROMISES.get(scope).push(promise);
9
- else
10
- PROMISES.set(scope, [promise]);
11
- };
12
- var defaultSampler = (_name, parentId) => {
13
- if (!parentId)
14
- return true;
15
- return tctx.is_sampled(parentId);
16
- };
17
- var sdk_object = {
18
- "telemetry.sdk.name": rian_name,
19
- "telemetry.sdk.version": rian_version
20
- };
21
- var create = (name, options) => {
22
- const spans = /* @__PURE__ */ new Set();
23
- const sampler = options.sampler || defaultSampler;
24
- const sampler_callable = typeof sampler !== "boolean";
25
- const span = (name2, parent) => {
26
- const should_sample = sampler_callable ? sampler(name2, parent, options.context) : sampler;
27
- const id = parent ? parent.child(should_sample) : tctx.make(should_sample);
28
- const span_obj = {
29
- id,
30
- parent,
31
- start: Date.now(),
32
- name: name2,
33
- events: [],
34
- context: {}
35
- };
36
- if (should_sample)
37
- spans.add(span_obj);
38
- const $ = (cb) => measureFn($, cb);
39
- $.traceparent = id;
40
- $.fork = (name3) => span(name3, id);
41
- $.set_context = (ctx) => {
42
- if (typeof ctx === "function")
43
- return void (span_obj.context = ctx(span_obj.context));
44
- Object.assign(span_obj.context, ctx);
45
- };
46
- $.add_event = (name3, attributes) => {
47
- span_obj.events.push({
48
- name: name3,
49
- timestamp: Date.now(),
50
- attributes: attributes || {}
51
- });
52
- };
53
- $.end = () => {
54
- if (span_obj.end == null)
55
- span_obj.end = Date.now();
56
- };
57
- return $;
58
- };
59
- const root = span(name, typeof options.traceparent === "string" ? tctx.parse(options.traceparent) : void 0);
60
- const endRoot = root.end.bind(root);
61
- root.end = async () => {
62
- endRoot();
63
- if (PROMISES.has(root))
64
- await Promise.all(PROMISES.get(root));
65
- return options.exporter(spans, {
66
- ...options.context || {},
67
- ...sdk_object
68
- });
69
- };
70
- return root;
71
- };
72
-
73
-
74
- exports.ADD_PROMISE = ADD_PROMISE;
75
- exports.PROMISES = PROMISES;
76
- exports.create = create;
1
+ const { measureFn:e } = require('rian/utils');const t = require('tctx');var n=(e,n)=>!n||t.is_sampled(n),a={"telemetry.sdk.name":"rian","telemetry.sdk.version":"0.2.3"},r=(r,o)=>{let s=new Set,d=new Set,i=o.sampler||n,p="boolean"!=typeof i,m=(n,a)=>{let r=p?i(n,a,o.context):i,c=a?a.child(r):t.make(r),l={id:c,parent:a,start:Date.now(),name:n,events:[],context:{}};r&&s.add(l);let x=t=>e(x,t);return x.traceparent=c,x.fork=e=>m(e,c),x.set_context=e=>{"function"!=typeof e?Object.assign(l.context,e):l.context=e(l.context)},x.add_event=(e,t)=>{l.events.push({name:e,timestamp:Date.now(),attributes:t||{}})},x.end=()=>{null==l.end&&(l.end=Date.now())},x.__add_promise=d.add.bind(d),x},c=m(r,"string"==typeof o.traceparent?t.parse(o.traceparent):void 0),l=c.end.bind(c);return c.end=async()=>(l(),d.size>0&&await Promise.all([...d.values()]),o.exporter(s,{...o.context||{},...a})),c};exports.create=r;
package/index.mjs CHANGED
@@ -1,76 +1 @@
1
- // src/index.ts
2
- import { name as rian_name, version as rian_version } from "rian/package.json";
3
- import * as tctx from "tctx";
4
- import { measureFn } from "rian/utils";
5
- var PROMISES = /* @__PURE__ */ new WeakMap();
6
- var ADD_PROMISE = (scope, promise) => {
7
- if (PROMISES.has(scope))
8
- PROMISES.get(scope).push(promise);
9
- else
10
- PROMISES.set(scope, [promise]);
11
- };
12
- var defaultSampler = (_name, parentId) => {
13
- if (!parentId)
14
- return true;
15
- return tctx.is_sampled(parentId);
16
- };
17
- var sdk_object = {
18
- "telemetry.sdk.name": rian_name,
19
- "telemetry.sdk.version": rian_version
20
- };
21
- var create = (name, options) => {
22
- const spans = /* @__PURE__ */ new Set();
23
- const sampler = options.sampler || defaultSampler;
24
- const sampler_callable = typeof sampler !== "boolean";
25
- const span = (name2, parent) => {
26
- const should_sample = sampler_callable ? sampler(name2, parent, options.context) : sampler;
27
- const id = parent ? parent.child(should_sample) : tctx.make(should_sample);
28
- const span_obj = {
29
- id,
30
- parent,
31
- start: Date.now(),
32
- name: name2,
33
- events: [],
34
- context: {}
35
- };
36
- if (should_sample)
37
- spans.add(span_obj);
38
- const $ = (cb) => measureFn($, cb);
39
- $.traceparent = id;
40
- $.fork = (name3) => span(name3, id);
41
- $.set_context = (ctx) => {
42
- if (typeof ctx === "function")
43
- return void (span_obj.context = ctx(span_obj.context));
44
- Object.assign(span_obj.context, ctx);
45
- };
46
- $.add_event = (name3, attributes) => {
47
- span_obj.events.push({
48
- name: name3,
49
- timestamp: Date.now(),
50
- attributes: attributes || {}
51
- });
52
- };
53
- $.end = () => {
54
- if (span_obj.end == null)
55
- span_obj.end = Date.now();
56
- };
57
- return $;
58
- };
59
- const root = span(name, typeof options.traceparent === "string" ? tctx.parse(options.traceparent) : void 0);
60
- const endRoot = root.end.bind(root);
61
- root.end = async () => {
62
- endRoot();
63
- if (PROMISES.has(root))
64
- await Promise.all(PROMISES.get(root));
65
- return options.exporter(spans, {
66
- ...options.context || {},
67
- ...sdk_object
68
- });
69
- };
70
- return root;
71
- };
72
- export {
73
- ADD_PROMISE,
74
- PROMISES,
75
- create
76
- };
1
+ import{measureFn as e}from"rian/utils";import*as t from"tctx";var n=(e,n)=>!n||t.is_sampled(n),a={"telemetry.sdk.name":"rian","telemetry.sdk.version":"0.2.3"},r=(r,o)=>{let s=new Set,d=new Set,i=o.sampler||n,p="boolean"!=typeof i,m=(n,a)=>{let r=p?i(n,a,o.context):i,c=a?a.child(r):t.make(r),l={id:c,parent:a,start:Date.now(),name:n,events:[],context:{}};r&&s.add(l);let x=t=>e(x,t);return x.traceparent=c,x.fork=e=>m(e,c),x.set_context=e=>{"function"!=typeof e?Object.assign(l.context,e):l.context=e(l.context)},x.add_event=(e,t)=>{l.events.push({name:e,timestamp:Date.now(),attributes:t||{}})},x.end=()=>{null==l.end&&(l.end=Date.now())},x.__add_promise=d.add.bind(d),x},c=m(r,"string"==typeof o.traceparent?t.parse(o.traceparent):void 0),l=c.end.bind(c);return c.end=async()=>(l(),d.size>0&&await Promise.all([...d.values()]),o.exporter(s,{...o.context||{},...a})),c};export{r as create};
package/license ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Marais Rossouw <me@marais.dev>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rian",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Effective tracing for the edge and origins",
5
5
  "keywords": [
6
6
  "opentelemetry",
@@ -17,11 +17,7 @@
17
17
  ],
18
18
  "repository": "maraisr/rian",
19
19
  "license": "MIT",
20
- "author": {
21
- "name": "Marais Rossouw",
22
- "email": "me@marais.dev",
23
- "url": "https://marais.io"
24
- },
20
+ "author": "Marais Rossow <me@marais.dev> (https://marais.io)",
25
21
  "sideEffects": false,
26
22
  "type": "module",
27
23
  "exports": {
@@ -58,13 +54,29 @@
58
54
  "utils/*"
59
55
  ],
60
56
  "scripts": {
61
- "build": "bundt"
57
+ "bench": "node -r tsm bench/index.ts",
58
+ "build": "bundt --minify",
59
+ "format": "prettier --write \"{*,{src,test}/**/*,examples/*/**,bench/*,.github/**/*}.+(ts|js|json|yml|md)\"",
60
+ "pretest": "pnpm run build",
61
+ "test": "uvu -r tsm test \".spec.m?ts$\"",
62
+ "typecheck": "tsc --noEmit --skipLibCheck"
62
63
  },
63
64
  "dependencies": {
64
65
  "flattie": "^1.1.0",
65
66
  "tctx": "^0.0.10"
66
67
  },
67
68
  "devDependencies": {
68
- "bundt": "2.0.0-next.5"
69
+ "@marais/prettier": "0.0.1",
70
+ "@marais/tsconfig": "0.0.3",
71
+ "bundt": "2.0.0-next.5",
72
+ "nanospy": "0.5.0",
73
+ "prettier": "2.7.1",
74
+ "tsm": "2.2.2",
75
+ "typescript": "4.8.4",
76
+ "uvu": "0.5.6"
77
+ },
78
+ "prettier": "@marais/prettier",
79
+ "volta": {
80
+ "node": "17.2.0"
69
81
  }
70
82
  }
package/readme.md ADDED
@@ -0,0 +1,278 @@
1
+ <div align="right">
2
+ <img src="files/logo-light.svg#gh-light-mode-only" alt="rian light mode logo" width="200px">
3
+ <img src="files/logo-dark.svg#gh-dark-mode-only" alt="rian dark mode logo" width="200px">
4
+ <br />
5
+ <br />
6
+
7
+ <p><code>npm add rian</code> doesn't overcomplicate tracing</p>
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
+ <a href="https://npm-stat.com/charts.html?package=rian">
13
+ <img src="https://badgen.net/npm/dw/rian?labelColor=black&color=black&cache=600" alt="downloads"/>
14
+ </a>
15
+ <a href="https://packagephobia.com/result?p=rian">
16
+ <img src="https://badgen.net/packagephobia/install/rian?labelColor=black&color=black" alt="size"/>
17
+ </a>
18
+ <a href="https://bundlephobia.com/result?p=rian">
19
+ <img src="https://badgen.net/bundlephobia/minzip/rian?labelColor=black&color=black" alt="size"/>
20
+ </a>
21
+ </span>
22
+
23
+ <br />
24
+ <br />
25
+ </div>
26
+
27
+ ## ⚡ Features
28
+
29
+ - 🤔 **Familiar** — looks very much like OpenTracing.
30
+
31
+ - ✅ **Simple** — `create` a tracer, and `.end()` a tracer, done.
32
+
33
+ - 🏎 **Performant** — check the [benchmarks](#-benchmark).
34
+
35
+ - 🪶 **Lightweight** — a mere 1Kb and next to no [dependencies](https://npm.anvaka.com/#/view/2d/rian/).
36
+
37
+ ## 🚀 Usage
38
+
39
+ > Visit [/examples](/examples) for more info!
40
+
41
+ ```ts
42
+ import { create } from 'rian';
43
+ import { measure } from 'rian/utils';
44
+ import { exporter } from 'rian/exporter.otel.http';
45
+
46
+ // ~> Where to send the spans.
47
+ const otel_endpoint = exporter((payload) =>
48
+ fetch('/traces/otlp', {
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('GET ~> /data', {
56
+ exporter: otel_endpoint,
57
+ });
58
+
59
+ // Let us trace
60
+
61
+ tracer.set_context({
62
+ user: request_context.user_id,
63
+ });
64
+
65
+ // ~> Wrap any method and be timed 🕺🏻
66
+ const data = await measure(tracer.fork('db::read'), get_data);
67
+
68
+ // ~> Maybe have some in-flow spanning
69
+ const span = tracer.span('process records');
70
+
71
+ for (let row of data) {
72
+ span.add_event('doing stuff', { id: row.id });
73
+ do_stuff(row);
74
+ }
75
+
76
+ span.end();
77
+
78
+ // ~> And finally let's export — will also end the root span.
79
+ await tracer.end();
80
+
81
+ /*
82
+ And we end up with something like this in our reporting tool:
83
+
84
+ [ GET ~> /data .................................... (1.2ms) ]
85
+ [ db::read .... (0.5ms) ]
86
+ [ process records .... (0.5ms) ]
87
+ */
88
+ ```
89
+
90
+ ## 🔎 API
91
+
92
+ #### Module: [`rian`](./packages/rian/src/index.ts)
93
+
94
+ The main and _default_ module responsible for creating and provisioning spans.
95
+
96
+ > 💡 Note ~> when providing span context values, please stick to
97
+ > [Semantic Conventions](https://github.com/opentracing/specification/blob/master/semantic_conventions.md), but won't be
98
+ > enforced.
99
+
100
+ #### Module: [`rian/exporter.zipkin`](./packages/rian/src/exporter.zipkin.ts)
101
+
102
+ Exports the spans created using the zipkin protocol and leaves the shipping up to you.
103
+
104
+ > 💡 Note ~> with the nature of zipkin, the `localEndpoint` must be set in your span context.
105
+ >
106
+ > <details><summary>Example</summary>
107
+ >
108
+ > ```ts
109
+ > const tracer = create('example', {
110
+ > context: {
111
+ > localEndpoint: {
112
+ > serviceName: 'my-service', // 👈 important part
113
+ > },
114
+ > },
115
+ > });
116
+ > ```
117
+ >
118
+ > Both of these are functionally equivalent. `service.name` will be used if no `localEndpoint.serviceName` is set.
119
+ >
120
+ > ```ts
121
+ > const tracer = create('example', {
122
+ > context: {
123
+ > 'service.name': 'my-service',
124
+ > },
125
+ > });
126
+ > ```
127
+ >
128
+ > </details>
129
+
130
+ #### Module: [`rian/exporter.otel.http`](./packages/rian/src/exporter.otel.http.ts)
131
+
132
+ Implements the OpenTelemetry protocol for use with http transports.
133
+
134
+ > 💡 Note ~> services require a `service.name` context value.
135
+ >
136
+ > <details><summary>Example</summary>
137
+ >
138
+ > ```ts
139
+ > const tracer = create('example', {
140
+ > context: {
141
+ > 'service.name': 'my-service', // 👈 important part
142
+ > },
143
+ > });
144
+ > ```
145
+ >
146
+ > </details>
147
+
148
+ ## 🧑‍🍳 Exporter Recipes
149
+
150
+ <details><summary>NewRelic</summary>
151
+
152
+ ```ts
153
+ import { create } from 'rian';
154
+ import { exporter } from 'rian/exporter.zipkin';
155
+
156
+ const newrelic = exporter((payload) =>
157
+ fetch('https://trace-api.newrelic.com/trace/v1', {
158
+ method: 'POST',
159
+ headers: {
160
+ 'api-key': '<your api key>',
161
+ 'content-type': 'application/json',
162
+ 'data-format': 'zipkin',
163
+ 'data-format-version': '2',
164
+ },
165
+ body: JSON.stringify(payload),
166
+ }),
167
+ );
168
+
169
+ const tracer = create('example', {
170
+ context: {
171
+ 'service.name': 'my-service', // 👈 important part
172
+ },
173
+ exporter: newrelic,
174
+ });
175
+ ```
176
+
177
+ [learn more](https://docs.newrelic.com/docs/distributed-tracing/trace-api/introduction-trace-api/)
178
+
179
+ </details>
180
+
181
+ <details><summary>LightStep</summary>
182
+
183
+ ```ts
184
+ import { create } from 'rian';
185
+ import { exporter } from 'rian/exporter.otel.http';
186
+
187
+ const lightstep = exporter((payload) =>
188
+ fetch('https://ingest.lightstep.com/traces/otlp/v0.6', {
189
+ method: 'POST',
190
+ headers: {
191
+ 'lightstep-access-token': '<your api key>',
192
+ 'content-type': 'application/json',
193
+ },
194
+ body: JSON.stringify(payload),
195
+ }),
196
+ );
197
+
198
+ const tracer = create('example', {
199
+ context: {
200
+ 'service.name': 'my-service', // 👈 important part
201
+ },
202
+ exporter: lightstep,
203
+ });
204
+ ```
205
+
206
+ [learn more](https://opentelemetry.lightstep.com/tracing/)
207
+
208
+ </details>
209
+
210
+ ## 🤔 Motivation
211
+
212
+ Firstly, what is `rian`? _trace_ in Irish is `rian`.
213
+
214
+ In efforts to be better observant citizens, we generally reach for the — NewRelic, LightStep, DataDog's. Which, and in
215
+ no offence to them, is bloated and slow! Where they more often than not do way too much or and relatively speaking, ship
216
+ useless traces. Which ramp up your bill — see... every span you trace, costs.
217
+
218
+ And here we are, introducing **rian** — a lightweight, fast effective tracer. Inspired by the giants in the industry,
219
+ OpenTracing and OpenTelemetry.
220
+
221
+ You might have not heard of those before — and that is okay. It means the design goals from OpenTelemetry or OpenTracing
222
+ has been met. They are frameworks built to abstract the telemetry part from vendors. So folk like NewRelic can wrap
223
+ their layers on top of open telemetry — and have libraries instrument theirs without knowing about the vendor. Which
224
+ allows consumers to ship those spans to the vendor of their choosing. OpenTracing has a very similar design goal, so
225
+ please do go checkout their documentation's, to help decide.
226
+
227
+ Rian does not intend to align or compete with them. rian's intent is to be used to instrument your application and
228
+ **only** your application. Rian is primed in that critical business paths — where you don't care " which handlers
229
+ MongoDB ran", or how many network calls your ORM made. Cardinality will destroy you. Although rian can scale to support
230
+ those as well. But the reality is; there are profiler tools far more capable — "right tool for the job".
231
+
232
+ Rian is simply a tracer you can use to see what your application is doing, have better insight into why something failed
233
+ and stitch it with your logs. It starts by capturing a [`w3c trace-context`](https://www.w3.org/TR/trace-context/),
234
+ tracing some business steps. "inbound request /data", "getting data", "sending email", or as granular as you'd like. And
235
+ have that forwarded onto all sub-services.
236
+
237
+ You see, the primary design goal is targeted at edge or service workers — where lean quick tracers is favoured.
238
+
239
+ Rian is still in active development, but ready for production!
240
+
241
+ ## 💨 Benchmark
242
+
243
+ > via the [`/bench`](/bench) directory with Node v17.2.0
244
+
245
+ ```
246
+ Validation :: single span
247
+ ✔ rian
248
+ ✔ opentelemetry
249
+ ✔ opentracing
250
+
251
+ Benchmark :: single span
252
+ rian x 137,181 ops/sec ±2.82% (82 runs sampled)
253
+ opentelemetry x 114,197 ops/sec ±11.37% (75 runs sampled)
254
+ opentracing x 33,363 ops/sec ±1.27% (89 runs sampled)
255
+
256
+ Validation :: child span
257
+ ✔ rian
258
+ ✔ opentelemetry
259
+ ✔ opentracing
260
+
261
+ Benchmark :: child span
262
+ rian x 75,567 ops/sec ±7.95% (77 runs sampled)
263
+ opentelemetry x 65,618 ops/sec ±8.45% (82 runs sampled)
264
+ opentracing x 15,452 ops/sec ±15.35% (77 runs sampled)
265
+
266
+ ```
267
+
268
+ > And please... I know these results are anything but the full story. But it's a number and point on comparison.
269
+
270
+ ## License
271
+
272
+ MIT © [Marais Rossouw](https://marais.io)
273
+
274
+ ##### Disclaimer
275
+
276
+ <sup>- NewRelic is a registered trademark of https://newrelic.com/ and not affiliated with this project.</sup><br />
277
+ <sup>- DataDog is a registered trademark of https://www.datadoghq.com/ and not affiliated with this project.</sup><br />
278
+ <sup>- LightStep is a registered trademark of https://lightstep.com/ and not affiliated with this project.</sup>
package/utils/index.js CHANGED
@@ -1,30 +1 @@
1
- // src/utils.ts
2
- const { ADD_PROMISE, PROMISES } = require('rian');
3
- var measureFn = (scope, fn, ...args) => {
4
- try {
5
- var r = fn(...args, scope), is_promise = r instanceof Promise;
6
- if (is_promise && !PROMISES.has(scope))
7
- ADD_PROMISE(scope, r.catch((e) => void scope.set_context({
8
- error: e
9
- })).finally(() => scope.end()));
10
- return r;
11
- } catch (e) {
12
- if (e instanceof Error)
13
- scope.set_context({
14
- error: e
15
- });
16
- throw e;
17
- } finally {
18
- if (is_promise !== true)
19
- scope.end();
20
- }
21
- };
22
- var measure = (scope, name, fn, ...args) => measureFn(scope.fork(name), fn, ...args);
23
- var wrap = (scope, name, fn) => function() {
24
- return measureFn(scope.fork(name), fn, ...arguments);
25
- };
26
-
27
-
28
- exports.measure = measure;
29
- exports.measureFn = measureFn;
30
- exports.wrap = wrap;
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,...o)=>r(t.fork(e),n,...o),e=(t,e,n)=>function(){return r(t.fork(e),n,...arguments)};exports.measure=t;exports.measureFn=r;exports.wrap=e;
package/utils/index.mjs CHANGED
@@ -1,30 +1 @@
1
- // src/utils.ts
2
- import { ADD_PROMISE, PROMISES } from "rian";
3
- var measureFn = (scope, fn, ...args) => {
4
- try {
5
- var r = fn(...args, scope), is_promise = r instanceof Promise;
6
- if (is_promise && !PROMISES.has(scope))
7
- ADD_PROMISE(scope, r.catch((e) => void scope.set_context({
8
- error: e
9
- })).finally(() => scope.end()));
10
- return r;
11
- } catch (e) {
12
- if (e instanceof Error)
13
- scope.set_context({
14
- error: e
15
- });
16
- throw e;
17
- } finally {
18
- if (is_promise !== true)
19
- scope.end();
20
- }
21
- };
22
- var measure = (scope, name, fn, ...args) => measureFn(scope.fork(name), fn, ...args);
23
- var wrap = (scope, name, fn) => function() {
24
- return measureFn(scope.fork(name), fn, ...arguments);
25
- };
26
- export {
27
- measure,
28
- measureFn,
29
- wrap
30
- };
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,...o)=>r(t.fork(e),n,...o),e=(t,e,n)=>function(){return r(t.fork(e),n,...arguments)};export{t as measure,r as measureFn,e as wrap};