Skip to content
This repository has been archived by the owner on May 23, 2023. It is now read-only.

Commit

Permalink
Initial, work-in-progress code
Browse files Browse the repository at this point in the history
  • Loading branch information
bcronin committed Jan 16, 2016
1 parent 22dae74 commit 1ff92f2
Show file tree
Hide file tree
Showing 15 changed files with 873 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .gitignore
@@ -0,0 +1,3 @@
node_modules/
npm-debug.log
dist/*
2 changes: 2 additions & 0 deletions .npmignore
@@ -0,0 +1,2 @@
node_modules/
npm-debug.log
72 changes: 72 additions & 0 deletions DEV.md
@@ -0,0 +1,72 @@
# Developer Notes

This is a work-in-progress implementation. Feedback and contributions are welcome.

This particular document is intended to summarize some development decisions made in the library to make moving the library forward easier and avoid revisiting past issues. The code history and Github issue history are helpful sources for more of this kind of information.

### Strictness

The library has a debug mode that enforces as many aspects of the public API as it reasonably can before passing data onto the implementation object. Often this is simply means validating the number and type of arguments. This is intended to discourage accidental (as well as intentional!) deviations in individual implementations from the OpenTracing specification. Particularly in debug mode, the library should err on the side of being overly restrictive (at least during initial development) as public APIs are almost always easier to make more flexible than more restrictive over time.

### Errors and Exceptions

The API layer throws Error exceptions *only* in debug builds.

In spirit of keeping the instrumentation from ever interfering with production application logic, the API layer does not handle error conditions in production builds. OpenTracing implementations may choose to handle them, but the implementations are encouraged to adhere to the principle that instrumentation code should not adversely affect the primary application code.

### No-op implementation

A design choice has been made that, for the purposes of integration simplicity and thus ease-of adoption, the `opentracing` JavaScript package is both the common API as well as a no-op implementation. This means that including the package should not require explicit configuration of a no-op implementation backend in order to run without instrumentation.

### API use of the Bridge Pattern ("pImpl idiom")

The API layer uses a bridge pattern to pass work to the specific tracing implementation. This is done instead of providing direct access to implementation-specific objects.

This is done primarily to encourage and, when possible enforce, standardization of the instrumentation code and conformance to the OpenTracing API. In JavaScript, which lacks a formal language-level concept of an "interface", the bridge pattern can emulate some of the advantages of more formal separation between interface and implementation.

For example, it is almost inevitable that there will be use cases for particular implementations that cannot be handled directly by the OpenTracing API (both valid uses and misguided ones, no doubt!). Encapsulating the implementation object as separate from the standard API, at the very least, encourages the deviations from the standard to be made more explicit.

For example, in the construed scenario below the `imp()` call below makes it self-documenting and obvious that `flushToStream()` is a non-standard, implementation-dependent method:

```
Tracer.startTrace("big_operation");
Tracer.imp().flushToStream(stream);
```

As a practical matter, such explicitness can be helpful for those new to tracing code (it self-documents what is standard and what is implementation-specific) as well as to reviewers of such code in highlighting deviations from the standard that may creep into a codebase.

## Open Questions / Issues / TODOS

*Note: the unresolved issues should be migrated to Github once the `opentracing-javascript` repository is created.*

**Don't the argument checks created overhead?**

Yes. Since webpack is being used, the code should be modified so these are compiled out of the production version. A Github issue should be opened on to properly exclude these from production builds of the package.

**How do I create span and log data retroactively?**

Example: creating a span retroactively after page load from `window.performance.timing` data.

This is [logged as an issue](https://github.com/opentracing/opentracing.github.io/issues/20) on the generalized OpenTracing API.

**How do I create a new Tracer instance (i.e. not the global singleton)?**

The current solution is to call `opentracing.initNewTracer(...)`. This is a *non-standard API* -- thus this is an open issue.

**What's the OpenTracing equivalent of `console.warn`?**

Current the API supports only info and error log statements.

**Should there be object pooling / reuse for all the ActiveSpan and ActiveSpan implementation objects?**

This optimization may make sense for a future version once the outward facing API is stabilized.

**Can I log spans before initializing the libray?**

Currently, no, as the underlying implementation object that would record these spans is not created until initialization.

This could be potentially useful as the startup information can be important and initialization order can sometimes be hard to control completely in a complex system of nested packages. However, this introduces difficulty as it would likely push implementation code to the OpenTracing API layer (i.e. some form of buffering until initialization was complete).

**What is an example use case for calling a newRootTraceContext()?**

...that could not be accomplished with a call to `startTrace()`?
19 changes: 19 additions & 0 deletions LICENSE
@@ -0,0 +1,19 @@
Copyright (c) 2016 Resonance Labs, Inc

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
83 changes: 81 additions & 2 deletions README.md
@@ -1,2 +1,81 @@
# opentracing-javascript
JavaScript implementation of Open Tracing API for the browser and server
# OpenTracing API for JavaScript

This library is a JavaScript implementation of Open Tracing API intended for use both on the server and in the browser.

**STATUS**: this library is still in development but should be ready shortly.

## Objectives

Distributed tracing and context propagation have become important analysis tools for today's multi-layer distributed systems comprised of numerous micro-services implemented in different languages. The success of these tools is dependent on pervasive instrumentation of applications and libraries with trace context propagation support.

The OpenTracing project (http://opentracing.github.io) provides a multi-lingual standard for application-level instrumentation that's loosely coupled to any particular downstream tracing or monitoring system. In this way, adding or switching tracing implementations becomes a single-step code change.

## Quick Start

Install the package:

```bash
npm install --save opentracing
```

In the JS code, add instrumentation to the operations to be tracked. This is composed primarily of using "spans" around operations of interest and adding log statements to capture useful data relevant to those operations.

```js
var http = require('http');
var Tracer = require('opentracing');

var span = Tracer.startTrace('http_request');
var opts = {
host : 'example.com',
method: 'GET',
port : '80',
path: '/',
};
http.request(opts, function (res) {
res.setEncoding('utf8');
res.on('error', function (err) {
span.info('Request error', err);
span.finish();
});
res.on('data', function (chunk) {
span.info('Data chunk received', chunk);
});
res.on('end', function(err) {
span.info('Request finished', err);
span.finish();
});
}).end();
```

To capture and make the tracing data actionable, simply update the `initialize` call to specify a backend of your choosing to pipe the data to. Note: the underlying implementation object is shared with between all inclusions of the `opentracing` package, so only the initialization code needs to concern itself with the implementation package.

```js
var Tracer = require('opentracing');
var TracingBackend = require('tracing-implementation-of-your-choice');

Tracer.initGlobalTracer(TracingBackend.create());
```

## Concepts

The main OpenTracing project (http://opentracing.github.io) provides the most up to date documentation on concepts, semantics, and best practices around effectively using OpenTracing.

## API

Coming soon!

## Usage Examples

Coming soon!

## Development

#### Unit tests

To run the unit tests:

```
npm test
```

*See [DEV.md](DEV.md) for additional detail.*
2 changes: 2 additions & 0 deletions dist/.gitignore
@@ -0,0 +1,2 @@
*
!.gitignore
35 changes: 35 additions & 0 deletions package.json
@@ -0,0 +1,35 @@
{
"name": "opentracing",
"version": "0.9.0",
"main": "dist/opentracing-node-debug.js",
"scripts": {
"webpack": "npm run webpack-node-debug && npm run webpack-node-prod && npm run webpack-browser-debug && npm run webpack-browser-prod",
"webpack-node-debug": "BUILD_PLATFORM=node BUILD_CONFIG=debug webpack --display-error-details",
"webpack-node-prod": "BUILD_PLATFORM=node BUILD_CONFIG=prod webpack --display-error-details",
"webpack-browser-debug": "BUILD_PLATFORM=browser BUILD_CONFIG=debug webpack --display-error-details",
"webpack-browser-prod": "BUILD_PLATFORM=browser BUILD_CONFIG=prod webpack --display-error-details",
"test": "node node_modules/mocha/bin/mocha -c test/unittest.js"
},
"repository": {
"type": "git",
"url": "https://github.com/opentracing/opentracing-javascript"
},
"dependencies": {
},
"devDependencies": {
"babel-core": "^6.3.26",
"babel-loader": "^6.2.0",
"babel-plugin-add-module-exports": "^0.1.2",
"babel-polyfill": "^6.3.14",
"babel-preset-es2015": "^6.3.13",
"chai": "^3.4.1",
"clone": "^1.0.2",
"colors": "^1.1.2",
"json-loader": "^0.5.4",
"mocha": "^2.3.4",
"shelljs": "^0.5.3",
"source-map-support": "^0.3.3",
"underscore": "^1.8.3",
"webpack": "^1.12.9"
}
}
6 changes: 6 additions & 0 deletions src/constants.js
@@ -0,0 +1,6 @@
'use strict';

// TODO: make this into a webpack build option so that production builds do
// not necessarily need to include the overhead of the argument checks.
// For the initial iterations, default to this being enabled.
export const API_CONFORMANCE_CHECKS = true;
5 changes: 5 additions & 0 deletions src/index.js
@@ -0,0 +1,5 @@
'use strict';

import Singleton from './singleton';

module.exports = new Singleton();
40 changes: 40 additions & 0 deletions src/singleton.js
@@ -0,0 +1,40 @@
'use strict';

import Tracer from './tracer';

/**
*
*/
export default class Singleton extends Tracer {

/**
* Creates the Singleton with no underlying implementation (i.e. defaults
* to no-op behavior for all functions).
*/
constructor() {
super();
}

/**
* [initialize description]
* @return {[type]} [description]
*/
initGlobalTracer(tracingImp) {
this._imp = tracingImp.newTracer();
}

/**
* Create a new Tracer object using the global implementation registered
* with initGlobalTracer. To reduce complexity, it is currently intentionally
* not possible to create a new Tracer with a different underlying
* implementation than the globally registered implementation.
*
* @return {[type]} [description]
*/
initNewTracer() {
if (!this._imp) {
return null;
}
return this._imp.newTracer();
}
}

0 comments on commit 1ff92f2

Please sign in to comment.