@lowerdeck/rpc-server 1.0.6 → 1.0.8

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/src/server.ts CHANGED
@@ -1,8 +1,15 @@
1
1
  import { internalServerError, isServiceError, notFoundError } from '@lowerdeck/error';
2
2
  import { getSentry } from '@lowerdeck/sentry';
3
+ import {
4
+ hasActiveSpan,
5
+ isTelemetryEnabled,
6
+ SpanStatusCode,
7
+ trace
8
+ } from '@lowerdeck/telemetry';
3
9
  import { Controller, Handler, ServiceRequest } from './controller';
4
10
 
5
11
  let Sentry = getSentry();
12
+ let tracer = trace.getTracer('lowerdeck.rpc-server.calls');
6
13
 
7
14
  export let createServer =
8
15
  (opts: {
@@ -57,59 +64,121 @@ export let createServer =
57
64
  }> => {
58
65
  let request = { ...req, body: call.payload };
59
66
 
60
- try {
61
- let handler = findHandler(call.name);
67
+ let executeCall = async () => {
68
+ try {
69
+ let handler = findHandler(call.name);
70
+
71
+ if (!handler) {
72
+ return {
73
+ request,
74
+ status: 404,
75
+ response: notFoundError({ entity: 'handler' }).toResponse()
76
+ };
77
+ }
78
+
79
+ let response = await handler.run(request, {});
62
80
 
63
- if (!handler) {
64
81
  return {
65
- request,
66
- status: 404,
67
- response: notFoundError({ entity: 'handler' }).toResponse()
82
+ status: 200,
83
+ request: req,
84
+ response: response.response
68
85
  };
86
+ } catch (e) {
87
+ console.error(e);
88
+
89
+ if (isServiceError(e)) {
90
+ if (e.data.status >= 500) {
91
+ Sentry.captureException(e, {
92
+ tags: { reqId }
93
+ });
94
+ }
95
+
96
+ return {
97
+ request,
98
+ status: e.data.status,
99
+ response: e.toResponse()
100
+ };
101
+ }
102
+
103
+ Sentry.captureException(e, {
104
+ tags: { reqId }
105
+ });
106
+
107
+ opts.onError?.({
108
+ callName: call.name,
109
+ callId: call.id,
110
+ request: req,
111
+ error: e,
112
+ reqId
113
+ });
114
+
115
+ throw e;
69
116
  }
117
+ };
70
118
 
71
- let response = await handler.run(request, {});
119
+ let canTrace = isTelemetryEnabled() && hasActiveSpan();
120
+ if (!canTrace) {
121
+ let result = await executeCall();
72
122
 
73
123
  return {
74
- status: 200,
75
- request: req,
76
- response: response.response
124
+ request: result.request,
125
+ status: result.status,
126
+ response: result.response
77
127
  };
78
- } catch (e) {
79
- console.error(e);
128
+ }
129
+
130
+ let callSpanName = `rpc call: ${call.name}`;
131
+ let callSpanOp = 'rpc.server.call';
80
132
 
81
- if (isServiceError(e)) {
82
- if (e.data.status >= 500) {
83
- Sentry.captureException(e, {
84
- tags: { reqId }
133
+ return await tracer.startActiveSpan(callSpanName, async span => {
134
+ span.setAttribute('sentry.op', callSpanOp);
135
+ span.setAttribute('rpc.system', 'lowerdeck');
136
+ span.setAttribute('rpc.method', call.name);
137
+ span.setAttribute('rpc.request_id', reqId);
138
+ span.setAttribute('rpc.call_id', call.id);
139
+ span.setAttribute('rpc.description', callSpanName);
140
+ span.setAttribute('sentry.description', callSpanName);
141
+
142
+ let finalize = (result: {
143
+ request: ServiceRequest;
144
+ status: number;
145
+ response: any;
146
+ }) => {
147
+ span.setAttribute('rpc.response.status_code', result.status);
148
+ if (result.status >= 500) {
149
+ span.setStatus({
150
+ code: SpanStatusCode.ERROR,
151
+ message: `RPC call failed with status ${result.status}`
85
152
  });
86
153
  }
87
154
 
88
- return {
89
- request,
90
- status: e.data.status,
91
- response: e.toResponse()
92
- };
93
- }
155
+ return result;
156
+ };
94
157
 
95
- Sentry.captureException(e, {
96
- tags: { reqId }
97
- });
158
+ try {
159
+ let result = await executeCall();
98
160
 
99
- opts.onError?.({
100
- callName: call.name,
101
- callId: call.id,
102
- request: req,
103
- error: e,
104
- reqId
105
- });
161
+ return finalize({
162
+ request: result.request,
163
+ status: result.status,
164
+ response: result.response
165
+ });
166
+ } catch (e) {
167
+ span.recordException(e as Error);
168
+ span.setStatus({
169
+ code: SpanStatusCode.ERROR,
170
+ message: e instanceof Error ? e.message : String(e)
171
+ });
106
172
 
107
- return {
108
- request,
109
- status: 500,
110
- response: internalServerError().toResponse()
111
- };
112
- }
173
+ return finalize({
174
+ request,
175
+ status: 500,
176
+ response: internalServerError().toResponse()
177
+ });
178
+ } finally {
179
+ span.end();
180
+ }
181
+ });
113
182
  };
114
183
 
115
184
  let runMany = async (