or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdhook-functions.mdhttp-instrumentation.mdindex.md

hook-functions.mddocs/

0

# Hook Functions

1

2

Hook functions provide custom logic for filtering requests and adding attributes during HTTP instrumentation lifecycle events. These functions allow fine-grained control over which requests are instrumented and what telemetry data is collected.

3

4

## Capabilities

5

6

### Request Filtering Functions

7

8

Functions used to determine whether incoming or outgoing requests should be instrumented.

9

10

```typescript { .api }

11

/**

12

* Function to determine if an incoming request should be ignored by instrumentation

13

* @param request - The incoming HTTP request

14

* @returns true to ignore the request, false to instrument it

15

*/

16

interface IgnoreIncomingRequestFunction {

17

(request: IncomingMessage): boolean;

18

}

19

20

/**

21

* Function to determine if an outgoing request should be ignored by instrumentation

22

* @param request - The outgoing HTTP request options

23

* @returns true to ignore the request, false to instrument it

24

*/

25

interface IgnoreOutgoingRequestFunction {

26

(request: RequestOptions): boolean;

27

}

28

```

29

30

**Usage Examples:**

31

32

```typescript

33

import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";

34

import type { IncomingMessage, RequestOptions } from "http";

35

36

const instrumentation = new HttpInstrumentation({

37

// Ignore specific incoming request patterns

38

ignoreIncomingRequestHook: (request: IncomingMessage) => {

39

const url = request.url || '';

40

const userAgent = request.headers['user-agent'] || '';

41

42

// Ignore health checks, metrics endpoints, and bot traffic

43

return url.startsWith('/health') ||

44

url.startsWith('/metrics') ||

45

url.startsWith('/_internal') ||

46

userAgent.includes('bot') ||

47

userAgent.includes('crawler');

48

},

49

50

// Ignore specific outgoing request patterns

51

ignoreOutgoingRequestHook: (request: RequestOptions) => {

52

const hostname = request.hostname || request.host || '';

53

const path = request.path || '';

54

55

// Ignore internal services and health checks

56

return hostname.includes('internal.company.com') ||

57

hostname === 'localhost' ||

58

hostname === '127.0.0.1' ||

59

path.includes('/health');

60

}

61

});

62

```

63

64

### Custom Attribute Functions

65

66

Functions used to add custom attributes to spans at different points in the request lifecycle.

67

68

```typescript { .api }

69

/**

70

* Function for adding custom attributes to spans after both request and response are processed

71

* @param span - The current span

72

* @param request - The HTTP request (ClientRequest for outgoing, IncomingMessage for incoming)

73

* @param response - The HTTP response (IncomingMessage for outgoing, ServerResponse for incoming)

74

*/

75

interface HttpCustomAttributeFunction {

76

(

77

span: Span,

78

request: ClientRequest | IncomingMessage,

79

response: IncomingMessage | ServerResponse

80

): void;

81

}

82

83

/**

84

* Function for adding custom attributes to spans during request processing

85

* @param span - The current span

86

* @param request - The HTTP request (ClientRequest for outgoing, IncomingMessage for incoming)

87

*/

88

interface HttpRequestCustomAttributeFunction {

89

(span: Span, request: ClientRequest | IncomingMessage): void;

90

}

91

92

/**

93

* Function for adding custom attributes to spans during response processing

94

* @param span - The current span

95

* @param response - The HTTP response (IncomingMessage for outgoing, ServerResponse for incoming)

96

*/

97

interface HttpResponseCustomAttributeFunction {

98

(span: Span, response: IncomingMessage | ServerResponse): void;

99

}

100

```

101

102

**Usage Examples:**

103

104

```typescript

105

import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";

106

import type { Span } from "@opentelemetry/api";

107

import type { ClientRequest, IncomingMessage, ServerResponse } from "http";

108

109

const instrumentation = new HttpInstrumentation({

110

// Add custom attributes during request processing

111

requestHook: (span: Span, request: ClientRequest | IncomingMessage) => {

112

// Common attributes for both incoming and outgoing requests

113

const userAgent = request.headers['user-agent'];

114

const contentType = request.headers['content-type'];

115

const requestId = request.headers['x-request-id'];

116

117

if (userAgent) {

118

span.setAttribute('http.user_agent.original', userAgent);

119

span.setAttribute('http.user_agent.is_mobile', userAgent.includes('Mobile'));

120

}

121

122

if (contentType) {

123

span.setAttribute('http.request.content_type', contentType);

124

}

125

126

if (requestId) {

127

span.setAttribute('http.request.id', requestId);

128

}

129

130

// Differentiate between incoming and outgoing requests

131

if ('method' in request) {

132

// This is an IncomingMessage (incoming request)

133

span.setAttribute('http.direction', 'incoming');

134

span.setAttribute('http.client.ip', request.socket.remoteAddress || '');

135

} else {

136

// This is a ClientRequest (outgoing request)

137

span.setAttribute('http.direction', 'outgoing');

138

}

139

},

140

141

// Add custom attributes during response processing

142

responseHook: (span: Span, response: IncomingMessage | ServerResponse) => {

143

const contentLength = response.headers['content-length'];

144

const cacheControl = response.headers['cache-control'];

145

const server = response.headers['server'];

146

147

if (contentLength) {

148

span.setAttribute('http.response.body.size', parseInt(contentLength));

149

}

150

151

if (cacheControl) {

152

span.setAttribute('http.response.cache_control', cacheControl);

153

}

154

155

if (server) {

156

span.setAttribute('http.response.server', server);

157

}

158

159

// Add custom performance categorization

160

if ('statusCode' in response && response.statusCode) {

161

const category = response.statusCode < 300 ? 'success' :

162

response.statusCode < 400 ? 'redirect' :

163

response.statusCode < 500 ? 'client_error' : 'server_error';

164

span.setAttribute('http.response.category', category);

165

}

166

},

167

168

// Add comprehensive attributes after complete request/response cycle

169

applyCustomAttributesOnSpan: (

170

span: Span,

171

request: ClientRequest | IncomingMessage,

172

response: IncomingMessage | ServerResponse

173

) => {

174

// Calculate request processing time

175

const endTime = Date.now();

176

const startTime = span.startTime[0] * 1000 + span.startTime[1] / 1_000_000;

177

const duration = endTime - startTime;

178

179

// Add performance categories

180

span.setAttribute('http.duration.category',

181

duration < 50 ? 'very_fast' :

182

duration < 200 ? 'fast' :

183

duration < 1000 ? 'moderate' :

184

duration < 5000 ? 'slow' : 'very_slow'

185

);

186

187

// Add size categories for responses

188

const contentLength = response.headers['content-length'];

189

if (contentLength) {

190

const size = parseInt(contentLength);

191

span.setAttribute('http.response.size.category',

192

size < 1024 ? 'small' :

193

size < 102400 ? 'medium' :

194

size < 1048576 ? 'large' : 'very_large'

195

);

196

}

197

}

198

});

199

```

200

201

### Span Start Attribute Functions

202

203

Functions used to add custom attributes before spans are created, allowing attributes to be set at span initialization.

204

205

```typescript { .api }

206

/**

207

* Function for adding custom attributes before an incoming request span is started

208

* @param request - The incoming HTTP request

209

* @returns Object containing attributes to add to the span

210

*/

211

interface StartIncomingSpanCustomAttributeFunction {

212

(request: IncomingMessage): Attributes;

213

}

214

215

/**

216

* Function for adding custom attributes before an outgoing request span is started

217

* @param request - The outgoing HTTP request options

218

* @returns Object containing attributes to add to the span

219

*/

220

interface StartOutgoingSpanCustomAttributeFunction {

221

(request: RequestOptions): Attributes;

222

}

223

```

224

225

**Usage Examples:**

226

227

```typescript

228

import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";

229

import type { Attributes } from "@opentelemetry/api";

230

import type { IncomingMessage, RequestOptions } from "http";

231

232

const instrumentation = new HttpInstrumentation({

233

// Add attributes at the start of incoming request spans

234

startIncomingSpanHook: (request: IncomingMessage): Attributes => {

235

const attributes: Attributes = {};

236

237

// Extract tenant/customer information

238

const tenantId = request.headers['x-tenant-id'];

239

const customerId = request.headers['x-customer-id'];

240

const apiVersion = request.headers['api-version'];

241

242

if (tenantId) {

243

attributes['tenant.id'] = tenantId;

244

}

245

246

if (customerId) {

247

attributes['customer.id'] = customerId;

248

}

249

250

if (apiVersion) {

251

attributes['api.version'] = apiVersion;

252

}

253

254

// Add request classification

255

const url = request.url || '';

256

if (url.startsWith('/api/v1/')) {

257

attributes['api.type'] = 'rest';

258

attributes['api.version'] = 'v1';

259

} else if (url.startsWith('/graphql')) {

260

attributes['api.type'] = 'graphql';

261

} else if (url.startsWith('/webhook')) {

262

attributes['api.type'] = 'webhook';

263

}

264

265

return attributes;

266

},

267

268

// Add attributes at the start of outgoing request spans

269

startOutgoingSpanHook: (request: RequestOptions): Attributes => {

270

const attributes: Attributes = {};

271

const hostname = request.hostname || request.host || '';

272

const path = request.path || '';

273

274

// Service identification

275

if (hostname.includes('api.stripe.com')) {

276

attributes['service.name'] = 'stripe';

277

attributes['service.type'] = 'payment';

278

} else if (hostname.includes('api.github.com')) {

279

attributes['service.name'] = 'github';

280

attributes['service.type'] = 'code_repository';

281

} else if (hostname.includes('amazonaws.com')) {

282

attributes['service.name'] = 'aws';

283

attributes['service.type'] = 'cloud_service';

284

}

285

286

// Operation classification

287

const method = request.method?.toUpperCase() || 'GET';

288

if (method === 'GET') {

289

attributes['operation.type'] = 'read';

290

} else if (method === 'POST' || method === 'PUT') {

291

attributes['operation.type'] = 'write';

292

} else if (method === 'DELETE') {

293

attributes['operation.type'] = 'delete';

294

}

295

296

// Add timeout information if specified

297

if (request.timeout) {

298

attributes['http.client.timeout'] = request.timeout;

299

}

300

301

return attributes;

302

}

303

});

304

```

305

306

## Advanced Hook Patterns

307

308

### Conditional Attribute Addition

309

310

```typescript

311

const instrumentation = new HttpInstrumentation({

312

requestHook: (span, request) => {

313

// Only add attributes for certain content types

314

const contentType = request.headers['content-type'] || '';

315

316

if (contentType.includes('application/json')) {

317

span.setAttribute('request.format', 'json');

318

319

// Add content length for JSON requests

320

const contentLength = request.headers['content-length'];

321

if (contentLength) {

322

span.setAttribute('request.json.size', parseInt(contentLength));

323

}

324

} else if (contentType.includes('multipart/form-data')) {

325

span.setAttribute('request.format', 'multipart');

326

} else if (contentType.includes('application/x-www-form-urlencoded')) {

327

span.setAttribute('request.format', 'form');

328

}

329

}

330

});

331

```

332

333

### Error Context Enhancement

334

335

```typescript

336

const instrumentation = new HttpInstrumentation({

337

applyCustomAttributesOnSpan: (span, request, response) => {

338

// Enhanced error context for failed requests

339

if ('statusCode' in response && response.statusCode && response.statusCode >= 400) {

340

span.setAttribute('error.type', 'http_error');

341

span.setAttribute('error.status_code', response.statusCode);

342

343

// Add more context for specific error ranges

344

if (response.statusCode >= 500) {

345

span.setAttribute('error.category', 'server_error');

346

span.setAttribute('error.severity', 'high');

347

} else if (response.statusCode >= 400) {

348

span.setAttribute('error.category', 'client_error');

349

span.setAttribute('error.severity', 'medium');

350

}

351

352

// Add request details for debugging

353

if ('url' in request) {

354

span.setAttribute('error.request.url', request.url || '');

355

}

356

if ('method' in request) {

357

span.setAttribute('error.request.method', request.method || '');

358

}

359

}

360

}

361

});

362

```