Skip to content

Commit c1b6eec

Browse files
authored
feat: memcached instrumentation (#539)
1 parent a8465a2 commit c1b6eec

File tree

19 files changed

+1131
-35
lines changed

19 files changed

+1131
-35
lines changed

.github/workflows/unit-test.yml

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,28 @@ jobs:
1414
container:
1515
image: ${{ matrix.container }}
1616
services:
17+
memcached:
18+
image: memcached:1.6.9-alpine
19+
ports:
20+
- 11211:11211
1721
mongo:
1822
image: mongo
1923
ports:
2024
- 27017:27017
25+
mysql:
26+
image: circleci/mysql:5.7
27+
env:
28+
MYSQL_USER: otel
29+
MYSQL_PASSWORD: secret
30+
MYSQL_DATABASE: circle_database
31+
MYSQL_ROOT_PASSWORD: rootpw
32+
ports:
33+
- 3306:3306
34+
options: >-
35+
--health-cmd="mysqladmin ping"
36+
--health-interval 10s
37+
--health-timeout 5s
38+
--health-retries 5
2139
postgres:
2240
image: circleci/postgres:9.6-alpine
2341
env:
@@ -39,25 +57,14 @@ jobs:
3957
--health-interval 10s
4058
--health-timeout 5s
4159
--health-retries 5
42-
mysql:
43-
image: circleci/mysql:5.7
44-
env:
45-
MYSQL_USER: otel
46-
MYSQL_PASSWORD: secret
47-
MYSQL_DATABASE: circle_database
48-
MYSQL_ROOT_PASSWORD: rootpw
49-
ports:
50-
- 3306:3306
51-
options: >-
52-
--health-cmd="mysqladmin ping"
53-
--health-interval 10s
54-
--health-timeout 5s
55-
--health-retries 5
5660
env:
57-
RUN_POSTGRES_TESTS: 1
58-
RUN_MYSQL_TESTS: 1
61+
RUN_MEMCACHED_TESTS: 1
5962
RUN_MONGODB_TESTS: 1
63+
RUN_MYSQL_TESTS: 1
64+
RUN_POSTGRES_TESTS: 1
6065
RUN_REDIS_TESTS: 1
66+
OPENTELEMETRY_MEMCACHED_HOST: memcached
67+
OPENTELEMETRY_MEMCACHED_PORT: 11211
6168
POSTGRES_USER: postgres
6269
POSTGRES_DB: circle_database
6370
POSTGRES_HOST: postgres

examples/memcached/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Overview
2+
3+
OpenTelemetry Memcached instrumentation allows user to automatically collect trace data from queries made by the client and export them to the backend of choice. This example does not showcase export functionality, but there are numerous other examples doing that: [`express`](../express), [`router`](../router).
4+
5+
## Running the Example
6+
7+
Created spans are printed out to stdout while running the example.
8+
9+
```sh
10+
npm install # install the dependencies
11+
npm run docker:start # start memcached server
12+
npm run start # run the example
13+
npm run docker:stop # spin down and clean up the docker container
14+
```
15+
16+
## LICENSE
17+
18+
Apache License 2.0

examples/memcached/index.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict';
2+
3+
require('./tracer')('example-resource');
4+
const Memcached = require('memcached');
5+
const assert = require('assert');
6+
7+
const KEY = '_KEY_';
8+
const VALUE = `RAND:${Math.random().toFixed(4)}`;
9+
const LT = 10;
10+
const client = new Memcached();
11+
12+
client.set(KEY, VALUE, LT, (err) => {
13+
assert.strictEqual(err, undefined);
14+
client.get(KEY, (err, result) => {
15+
assert.strictEqual(err, undefined);
16+
assert.strictEqual(result, VALUE);
17+
console.log('Sleeping 5 seconds before shutdown to ensure all records are flushed.');
18+
setTimeout(() => { console.log('Completed.'); }, 5000);
19+
});
20+
});

examples/memcached/package.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "memcached-example",
3+
"private": true,
4+
"version": "0.22.0",
5+
"description": "Example of Memcached client with OpenTelemetry",
6+
"main": "index.js",
7+
"scripts": {
8+
"docker:start": "docker run --rm -d --name otel-memcached -p 11211:11211 memcached:1.6.9-alpine",
9+
"docker:stop": "docker rm -f otel-memcached",
10+
"start": "node index.js"
11+
},
12+
"repository": {
13+
"type": "git",
14+
"url": "git+ssh://[email protected]/open-telemetry/opentelemetry-js-contrib.git"
15+
},
16+
"keywords": [
17+
"opentelemetry",
18+
"instrumentation",
19+
"memcached",
20+
"tracing"
21+
],
22+
"engines": {
23+
"node": ">=8.5.0"
24+
},
25+
"author": "OpenTelemetry Authors",
26+
"license": "Apache-2.0",
27+
"bugs": {
28+
"url": "https://github.com/open-telemetry/opentelemetry-js-contrib/issues"
29+
},
30+
"dependencies": {
31+
"@opentelemetry/api": "^1.0.1",
32+
"@opentelemetry/instrumentation": "^0.22.0",
33+
"@opentelemetry/instrumentation-memcached": "^0.22.0",
34+
"@opentelemetry/node": "^0.22.0",
35+
"@opentelemetry/tracing": "^0.22.0",
36+
"memcached": "^2.2.2"
37+
},
38+
"homepage": "https://github.com/open-telemetry/opentelemetry-js-contrib#readme"
39+
}

examples/memcached/tracer.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use strict';
2+
3+
const opentelemetry = require('@opentelemetry/api');
4+
5+
const { diag, DiagConsoleLogger, DiagLogLevel } = opentelemetry;
6+
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.VERBOSE);
7+
8+
const { registerInstrumentations } = require('@opentelemetry/instrumentation');
9+
const { NodeTracerProvider } = require('@opentelemetry/node');
10+
const { SimpleSpanProcessor, ConsoleSpanExporter } = require('@opentelemetry/tracing');
11+
const { Resource } = require('@opentelemetry/resources');
12+
const { ResourceAttributes } = require('@opentelemetry/semantic-conventions');
13+
14+
const { MemcachedInstrumentation } = require('@opentelemetry/instrumentation-memcached');
15+
16+
module.exports = (serviceName) => {
17+
const provider = new NodeTracerProvider({
18+
resource: new Resource({
19+
[ResourceAttributes.SERVICE_NAME]: serviceName,
20+
}),
21+
});
22+
registerInstrumentations({
23+
tracerProvider: provider,
24+
instrumentations: [
25+
new MemcachedInstrumentation(),
26+
],
27+
});
28+
29+
const exporter = new ConsoleSpanExporter();
30+
31+
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
32+
33+
// Initialize the OpenTelemetry APIs to use the NodeTracerProvider bindings
34+
provider.register();
35+
36+
return opentelemetry.trace.getTracer('memcached-example');
37+
};

packages/opentelemetry-test-utils/testUtils.ts

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,18 @@ import {
2929
hrTimeToMicroseconds,
3030
} from '@opentelemetry/core';
3131

32-
export function startDocker(db: 'redis' | 'mysql' | 'postgres') {
33-
let dockerRunCmd;
34-
switch (db) {
35-
case 'redis':
36-
dockerRunCmd = `docker run -d -p 63790:6379 --name ot${db} ${db}:alpine`;
37-
break;
38-
39-
case 'mysql':
40-
dockerRunCmd = `docker run --rm -d -e MYSQL_ROOT_PASSWORD=rootpw -e MYSQL_DATABASE=test_db -e MYSQL_USER=otel -e MYSQL_PASSWORD=secret -p 33306:3306 --name ot${db} circleci/${db}:5.7`;
41-
break;
42-
43-
case 'postgres':
44-
dockerRunCmd = `docker run -d -p 54320:5432 -e POSTGRES_PASSWORD=postgres --name ot${db} ${db}:alpine`;
45-
break;
46-
}
32+
const dockerRunCmds = {
33+
redis: 'docker run --rm -d --name otel-redis -p 63790:6379 redis:alpine',
34+
mysql:
35+
'docker run --rm -d --name otel-mysql -p 33306:3306 -e MYSQL_ROOT_PASSWORD=rootpw -e MYSQL_DATABASE=test_db -e MYSQL_USER=otel -e MYSQL_PASSWORD=secret circleci/mysql:5.7',
36+
postgres:
37+
'docker run --rm -d --name otel-postgres -p 54320:5432 -e POSTGRES_PASSWORD=postgres postgres:alpine',
38+
memcached:
39+
'docker run --rm -d --name otel-memcached -p 11211:11211 memcached:1.6.9-alpine',
40+
};
4741

48-
const tasks = [run(dockerRunCmd)];
42+
export function startDocker(db: keyof typeof dockerRunCmds) {
43+
const tasks = [run(dockerRunCmds[db])];
4944

5045
for (let i = 0; i < tasks.length; i++) {
5146
const task = tasks[i];
@@ -58,9 +53,9 @@ export function startDocker(db: 'redis' | 'mysql' | 'postgres') {
5853
return true;
5954
}
6055

61-
export function cleanUpDocker(db: 'redis' | 'mysql' | 'postgres') {
62-
run(`docker stop ot${db}`);
63-
run(`docker rm ot${db}`);
56+
export function cleanUpDocker(db: keyof typeof dockerRunCmds) {
57+
run(`docker stop otel-${db}`);
58+
run(`docker rm otel-${db}`);
6459
}
6560

6661
function run(cmd: string) {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
build
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module.exports = {
2+
"env": {
3+
"mocha": true,
4+
"node": true
5+
},
6+
...require('../../../eslint.config.js')
7+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/bin
2+
/coverage
3+
/doc
4+
/test

0 commit comments

Comments
 (0)