Skip to content
This repository was archived by the owner on Jan 21, 2026. It is now read-only.

fix: class-ify cls implementations#708

Merged
kjin merged 8 commits intogoogleapis:masterfrom
kjin:cls-new-2
Apr 19, 2018
Merged

fix: class-ify cls implementations#708
kjin merged 8 commits intogoogleapis:masterfrom
kjin:cls-new-2

Conversation

@kjin
Copy link
Copy Markdown
Contributor

@kjin kjin commented Mar 30, 2018

Summary

This PR refactors the CLS implementations as classes implementing a common interface. There are a number of implementations offered:

  • UniversalCLS treats all code as running in the same continuation.
  • AsyncHooksCLS uses async_hooks to propagate context within a continuation, with no semantic changes w.r.t the original implementation.
  • AsyncListenerCLS uses async-listener to propagate context with async-listener (a la continuation-local-storage), also with no semantic changes compared to the original implementation.
  • TraceCLS is a meta-implementation that wraps either of the Async* mechanisms, based on its config object. When enabled it uses either AsyncHooksCLS or AsyncListenerCLS with a default value (when there is no available context) set to { type: UNCORRELATED }. When disabled, it uses UniversalCLS with the universal value set to { type: UNTRACED }. I do not expect this to be a semantic change, as this roughly describes the current implementation today (that when the Trace Agent is disabled, all spans are UNTRACED phantom spans).

The reasons for making such a change is as follows:

  • The current async_hooks implementation is treated as an implementation of the continuation-local-storage Namespace interface, but we should de-couple the two implementations by instead introducing our own common interface.
  • More modularity. This can help us test code -- both CLS as well as the Trace Agent in isolation.
  • It's possible that we would need to support more than two mechanisms (or even slight differences within a single mechanism) for CLS. This paves the road towards achieving that.
    • In particular, UniversalCLS may be useful in environments where CLS doesn't matter.

Change Overview

Bold denotes a new file, and strikethrough denotes a removed file.

  • src
    • cls.ts: Formerly exposed functions to manipulate a c-l-s Namespace (implementation of which is dependent on GCLOUD_TRACE_NEW_CONTEXT).
    • cls-ah.ts: Formerly an implementation of the Namespace interface from continuation-local-storage using async_hooks.
    • cls.ts: Exports TraceCLS as described above.
    • cls
      • base.ts: Exports the CLS interface definition.
      • async-hooks.ts: Exports an implementation of the CLS interface based on async_hooks.
      • async-listener.ts: Exports an implementation of the CLS interface based on async-listener.
      • universal.ts: Exports UniversalCLS as described above.

Reading the environmental variable GCLOUD_TRACE_NEW_CONTEXT is now done in index.ts.

@googlebot googlebot added the cla: yes This human has signed the Contributor License Agreement. label Mar 30, 2018
@kjin kjin force-pushed the cls-new-2 branch 9 times, most recently from b8c45f5 to 57ca019 Compare April 3, 2018 20:49
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 3, 2018

Codecov Report

Merging #708 into master will decrease coverage by 0.02%.
The diff coverage is 89.93%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #708      +/-   ##
==========================================
- Coverage   90.76%   90.74%   -0.03%     
==========================================
  Files          28       30       +2     
  Lines        1495     1556      +61     
  Branches      296      304       +8     
==========================================
+ Hits         1357     1412      +55     
- Misses         59       61       +2     
- Partials       79       83       +4
Impacted Files Coverage Δ
src/util.ts 95.58% <100%> (+0.06%) ⬆️
src/trace-api.ts 94.38% <100%> (ø) ⬆️
src/cls/async-listener.ts 100% <100%> (ø)
src/index.ts 83.33% <63.63%> (-8.67%) ⬇️
src/cls/universal.ts 76.92% <76.92%> (ø)
src/cls.ts 93.47% <93.18%> (+12.52%) ⬆️
src/cls/async-hooks.ts 95.65% <95.65%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 395a0c7...8c2198b. Read the comment docs.

@kjin kjin requested review from DominicKramer, jinwoo and ofrobots and removed request for DominicKramer, jinwoo and ofrobots April 12, 2018 17:24
Copy link
Copy Markdown
Contributor

@ofrobots ofrobots left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still going though, but left some high level comments that will probably need discussion.

Comment thread src/cls.ts
this.logger = logger;
const uncorrelated: RootContext = {type: SpanDataType.UNCORRELATED};
const untraced: RootContext = {type: SpanDataType.UNTRACED};
const useAH = config.mechanism === 'async-hooks' && asyncHooksAvailable;

This comment was marked as spam.

This comment was marked as spam.

Comment thread src/cls.ts Outdated
`propagation is not available in Node ${process.version}.`,
'Falling back to using async-listener.');
} else {
this.logger.warn(

This comment was marked as spam.

Comment thread src/cls.ts
// special case where _all_ requests are explicitly not being traced,
// so return UNTRACED_SPAN to be consistent with that.
return UNTRACED_SPAN;
disable(): void {

This comment was marked as spam.

This comment was marked as spam.

Copy link
Copy Markdown
Contributor

@ofrobots ofrobots left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is more to look at, but I will leave it here for the initial round.

Comment thread src/cls.ts
@@ -1,5 +1,5 @@
/**
* Copyright 2015 Google Inc. All Rights Reserved.
* Copyright 2018 Google LLC

This comment was marked as spam.

Comment thread src/cls/base.ts Outdated
* path in which they were attached to the EventEmitter object.
* @param ee The EventEmitter to bind. This instance will be mutated.
*/
patchEmitterToPropagateContext<T>(ee: EventEmitter): void;

This comment was marked as spam.

This comment was marked as spam.

Comment thread src/cls/async-hooks.ts Outdated
private hook: asyncHooksModule.AsyncHook;
private enabled = false;

constructor(defaultContext: Context) {

This comment was marked as spam.

Comment thread src/cls/async-hooks.ts Outdated
* module.
*/
export class AsyncHooksCLS<Context extends {}> implements CLS<Context> {
private current: {value: Context};

This comment was marked as spam.

This comment was marked as spam.

Comment thread src/cls/async-hooks.ts
runWithNewContext<T>(fn: Func<T>): T {
const oldContext = this.current.value;
this.current.value = this.defaultContext;
const res = fn();

This comment was marked as spam.

This comment was marked as spam.

Comment thread src/cls/async-hooks.ts
const contextWrapper = function(this: {}) {
const oldContext = current.value;
current.value = boundContext;
const res = fn.apply(this, arguments) as T;

This comment was marked as spam.

This comment was marked as spam.

Comment thread src/cls/async-hooks.ts Outdated

const EVENT_EMITTER_METHODS: Array<keyof EventEmitter> =
['addListener', 'on', 'once', 'prependListener', 'prependOnceListener'];
const WRAPPED = Symbol('context_wrapped');

This comment was marked as spam.

This comment was marked as spam.

Comment thread src/cls/async-hooks.ts Outdated
}
});
}
} No newline at end of file

This comment was marked as spam.

Comment thread src/cls/base.ts
*
* CLS stands for continuation-local storage.
*/
export interface CLS<Context extends {}> {

This comment was marked as spam.

This comment was marked as spam.

Comment thread src/cls/base.ts
/**
* Enables this instance.
*/
enable(): void;

This comment was marked as spam.

This comment was marked as spam.

@kjin kjin force-pushed the cls-new-2 branch 3 times, most recently from 52e7e65 to 03bc2df Compare April 13, 2018 18:22
Comment thread src/cls.ts Outdated
export class TraceCLS implements CLS<RootContext> {
private currentCLS: CLS<RootContext>;
// CLSClass is a constructor.
// tslint:disable-next-line:variable-name

This comment was marked as spam.

Comment thread src/cls.ts Outdated
*/
readonly rootSpanStackOffset: number;

constructor(logger: Logger, config: TraceCLSConfig) {

This comment was marked as spam.

Comment thread src/cls.ts
return cls.createNamespace(TRACE_NAMESPACE);
}
isEnabled(): boolean {
return this.enabled;

This comment was marked as spam.

This comment was marked as spam.

Comment thread src/cls/async-hooks.ts Outdated
const EVENT_EMITTER_METHODS: Array<keyof EventEmitter> =
['addListener', 'on', 'once', 'prependListener', 'prependOnceListener'];
// A symbol used to check if a method has been wrapped for context.
const WRAPPED = Symbol('@google-cloud/trace-agent::AsyncHooksCLS::WRAPPED');

This comment was marked as spam.

This comment was marked as spam.

Comment thread src/cls.ts
import * as semver from 'semver';

import {AsyncHooksCLS} from './cls/async-hooks';
import {AsyncListenerCLS} from './cls/async-listener';

This comment was marked as spam.

This comment was marked as spam.

Comment thread src/cls/universal.ts Outdated
}

patchEmitterToPropagateContext(ee: EventEmitter): void {}
} No newline at end of file

This comment was marked as spam.

Comment thread src/cls/universal.ts Outdated
export class UniversalCLS<Context> implements CLS<Context> {
private enabled = false;

constructor(private defaultContext: Context) {}

This comment was marked as spam.

This comment was marked as spam.

@kjin kjin changed the title refactor: class-ify cls implementations fix: class-ify cls implementations Apr 17, 2018
Comment thread src/cls/async-listener.ts
* limitations under the License.
*/

import * as clsModule from 'continuation-local-storage';

This comment was marked as spam.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

cla: yes This human has signed the Contributor License Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants