Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: memcached instrumentation #539

Merged
merged 25 commits into from Jun 30, 2021
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ba4ebfa
feat: first iteration of memcache instrumentation
rauno56 Jun 16, 2021
ab4cd1e
feat: add memcached docker commands for tests
rauno56 Jun 16, 2021
0be9b2f
test: test collecting statements
rauno56 Jun 16, 2021
5508b38
refactor: finish the instrumentation and the docs
rauno56 Jun 17, 2021
8e6e290
style: sort db configs in unit tests
rauno56 Jun 17, 2021
da68c7a
test: add memcached service to tests
rauno56 Jun 17, 2021
d8f5a09
style: lint
rauno56 Jun 17, 2021
584eb5a
chore: update versions
rauno56 Jun 17, 2021
52bd8d6
style: lint fix test utils
rauno56 Jun 17, 2021
d7defc1
fix: add env cars for memcached host and port for tests
rauno56 Jun 17, 2021
37f1b6b
test: fix hardcoded localhost values from tests
rauno56 Jun 17, 2021
a6d8e63
feat: rename the unnamed span to something more descriptive
rauno56 Jun 17, 2021
e8cbfac
style: lint-fix
rauno56 Jun 17, 2021
636b295
docs: add a disclamer about the dangers of `collectCommand`
rauno56 Jun 18, 2021
a95dcfc
Merge branch 'main' into feat/memcached-instrumentation
rauno56 Jun 28, 2021
d2d3361
refactor: use component logger
rauno56 Jun 28, 2021
b3cbb6a
feat: update versions
rauno56 Jun 28, 2021
875f606
Merge branch 'main' into feat/memcached-instrumentation
rauno56 Jun 28, 2021
9ec9897
feat: default to {} in setConfig
rauno56 Jun 28, 2021
27a6921
refactor: rename `collecCommand` configuration option
rauno56 Jun 28, 2021
4ef4fd2
feat: add example for memcached
rauno56 Jun 28, 2021
607b31c
fix: use semantic attribute for db.statement
rauno56 Jun 28, 2021
4668d9f
fix: use `serviceName` parameter
rauno56 Jun 28, 2021
d92c8ce
test: test cb context
rauno56 Jun 28, 2021
9fde92b
feat: return to parent context in callback
rauno56 Jun 28, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
39 changes: 23 additions & 16 deletions .github/workflows/unit-test.yml
Expand Up @@ -14,10 +14,28 @@ jobs:
container:
image: ${{ matrix.container }}
services:
memcached:
image: memcached:1.6.9-alpine
ports:
- 11211:11211
mongo:
image: mongo
ports:
- 27017:27017
mysql:
image: circleci/mysql:5.7
env:
MYSQL_USER: otel
MYSQL_PASSWORD: secret
MYSQL_DATABASE: circle_database
MYSQL_ROOT_PASSWORD: rootpw
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
postgres:
image: circleci/postgres:9.6-alpine
env:
Expand All @@ -39,25 +57,14 @@ jobs:
--health-interval 10s
--health-timeout 5s
--health-retries 5
mysql:
image: circleci/mysql:5.7
env:
MYSQL_USER: otel
MYSQL_PASSWORD: secret
MYSQL_DATABASE: circle_database
MYSQL_ROOT_PASSWORD: rootpw
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
RUN_POSTGRES_TESTS: 1
RUN_MYSQL_TESTS: 1
RUN_MEMCACHED_TESTS: 1
RUN_MONGODB_TESTS: 1
RUN_MYSQL_TESTS: 1
RUN_POSTGRES_TESTS: 1
RUN_REDIS_TESTS: 1
OPENTELEMETRY_MEMCACHED_HOST: memcached
OPENTELEMETRY_MEMCACHED_PORT: 11211
POSTGRES_USER: postgres
POSTGRES_DB: circle_database
POSTGRES_HOST: postgres
Expand Down
18 changes: 18 additions & 0 deletions examples/memcached/README.md
@@ -0,0 +1,18 @@
# Overview

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).

## Running the Example

Created spans are printed out to stdout while running the example.

```sh
npm install # install the dependencies
npm run docker:start # start memcached server
npm run start # run the example
npm run docker:stop # spin down and clean up the docker container
```

## LICENSE

Apache License 2.0
20 changes: 20 additions & 0 deletions examples/memcached/index.js
@@ -0,0 +1,20 @@
'use strict';

require('./tracer')('example-resource');
const Memcached = require('memcached');
const assert = require('assert');

const KEY = '_KEY_';
const VALUE = `RAND:${Math.random().toFixed(4)}`;
const LT = 10;
const client = new Memcached();

client.set(KEY, VALUE, LT, (err) => {
assert.strictEqual(err, undefined);
client.get(KEY, (err, result) => {
assert.strictEqual(err, undefined);
assert.strictEqual(result, VALUE);
console.log('Sleeping 5 seconds before shutdown to ensure all records are flushed.');
setTimeout(() => { console.log('Completed.'); }, 5000);
});
});
39 changes: 39 additions & 0 deletions examples/memcached/package.json
@@ -0,0 +1,39 @@
{
"name": "memcached-example",
"private": true,
"version": "0.22.0",
"description": "Example of Memcached client with OpenTelemetry",
"main": "index.js",
"scripts": {
"docker:start": "docker run --rm -d --name otel-memcached -p 11211:11211 memcached:1.6.9-alpine",
"docker:stop": "docker rm -f otel-memcached",
"start": "node index.js"
},
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/open-telemetry/opentelemetry-js-contrib.git"
},
"keywords": [
"opentelemetry",
"instrumentation",
"memcached",
"tracing"
],
"engines": {
"node": ">=8.5.0"
},
"author": "OpenTelemetry Authors",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/open-telemetry/opentelemetry-js-contrib/issues"
},
"dependencies": {
"@opentelemetry/api": "^1.0.1",
"@opentelemetry/instrumentation": "^0.22.0",
"@opentelemetry/instrumentation-memcached": "^0.22.0",
"@opentelemetry/node": "^0.22.0",
"@opentelemetry/tracing": "^0.22.0",
"memcached": "^2.2.2"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js-contrib#readme"
}
37 changes: 37 additions & 0 deletions examples/memcached/tracer.js
@@ -0,0 +1,37 @@
'use strict';

const opentelemetry = require('@opentelemetry/api');

const { diag, DiagConsoleLogger, DiagLogLevel } = opentelemetry;
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.VERBOSE);

const { registerInstrumentations } = require('@opentelemetry/instrumentation');
const { NodeTracerProvider } = require('@opentelemetry/node');
const { SimpleSpanProcessor, ConsoleSpanExporter } = require('@opentelemetry/tracing');
const { Resource } = require('@opentelemetry/resources');
const { ResourceAttributes } = require('@opentelemetry/semantic-conventions');

const { MemcachedInstrumentation } = require('@opentelemetry/instrumentation-memcached');

module.exports = (serviceName) => {
const provider = new NodeTracerProvider({
resource: new Resource({
[ResourceAttributes.SERVICE_NAME]: serviceName,
}),
});
registerInstrumentations({
tracerProvider: provider,
instrumentations: [
new MemcachedInstrumentation(),
],
});

const exporter = new ConsoleSpanExporter();

provider.addSpanProcessor(new SimpleSpanProcessor(exporter));

// Initialize the OpenTelemetry APIs to use the NodeTracerProvider bindings
provider.register();

return opentelemetry.trace.getTracer('memcached-example');
};
33 changes: 14 additions & 19 deletions packages/opentelemetry-test-utils/testUtils.ts
Expand Up @@ -29,23 +29,18 @@ import {
hrTimeToMicroseconds,
} from '@opentelemetry/core';

export function startDocker(db: 'redis' | 'mysql' | 'postgres') {
let dockerRunCmd;
switch (db) {
case 'redis':
dockerRunCmd = `docker run -d -p 63790:6379 --name ot${db} ${db}:alpine`;
break;

case 'mysql':
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`;
break;

case 'postgres':
dockerRunCmd = `docker run -d -p 54320:5432 -e POSTGRES_PASSWORD=postgres --name ot${db} ${db}:alpine`;
break;
}
const dockerRunCmds = {
redis: 'docker run --rm -d --name otel-redis -p 63790:6379 redis:alpine',
mysql:
'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',
postgres:
'docker run --rm -d --name otel-postgres -p 54320:5432 -e POSTGRES_PASSWORD=postgres postgres:alpine',
memcached:
'docker run --rm -d --name otel-memcached -p 11211:11211 memcached:1.6.9-alpine',
};

const tasks = [run(dockerRunCmd)];
export function startDocker(db: keyof typeof dockerRunCmds) {
const tasks = [run(dockerRunCmds[db])];

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

export function cleanUpDocker(db: 'redis' | 'mysql' | 'postgres') {
run(`docker stop ot${db}`);
run(`docker rm ot${db}`);
export function cleanUpDocker(db: keyof typeof dockerRunCmds) {
run(`docker stop otel-${db}`);
run(`docker rm otel-${db}`);
}

function run(cmd: string) {
Expand Down
@@ -0,0 +1 @@
build
@@ -0,0 +1,7 @@
module.exports = {
"env": {
"mocha": true,
"node": true
},
...require('../../../eslint.config.js')
}
@@ -0,0 +1,4 @@
/bin
/coverage
/doc
/test