Skip to content

Commit

Permalink
Add Environment & Services support (#551)
Browse files Browse the repository at this point in the history
Co-authored-by: Vera Reynolds <vreynolds@users.noreply.github.com>
  • Loading branch information
MikeGoldsmith and vreynolds committed Mar 17, 2022
1 parent 19f8fdc commit 5510b37
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 9 deletions.
6 changes: 5 additions & 1 deletion lib/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ const process = require("process"),
pkg = require("../../package.json"),
debug = require("debug")(`${pkg.name}:event`),
LibhoneyImpl = require("./libhoney"),
MockImpl = require("./mock");
MockImpl = require("./mock"),
utils = require("../util");

const { honeycomb, aws, w3c, util } = propagation;

Expand Down Expand Up @@ -38,6 +39,9 @@ module.exports = {
}
debug(`using impl: ${impl == LibhoneyImpl ? "libhoney-event" : "mock"}`);
apiImpl = new impl(opts);

// tell honeycomb propagator whether we should propagate dataset
honeycomb.setPropagateDataset(utils.isClassic(opts.writeKey));
},

traceActive() {
Expand Down
92 changes: 89 additions & 3 deletions lib/api/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,103 @@ jest.mock("../deterministic_sampler");

beforeEach(() => {
api._resetForTesting();
api.configure({ impl: "libhoney-event", transmission: "mock", writeKey: "abc123" });
api.configure({
impl: "libhoney-event",
transmission: "mock",
writeKey: "e38be416d0d68f9ed1e96432ac1a3380",
});
});

test("libhoney default config", () => {
test("libhoney default config - classic", () => {
const honey = api._apiForTesting().honey;
expect(honey.transmission.constructorArg.apiHost).toBe("https://api.honeycomb.io");
expect(honey.transmission.constructorArg.dataset).toBe("nodejs");
expect(honey.transmission.constructorArg.writeKey).toBe("abc123");
expect(honey.transmission.constructorArg.writeKey).toBe("e38be416d0d68f9ed1e96432ac1a3380");
expect(honey.transmission.constructorArg.userAgentAddition).toBe(
`honeycomb-beeline/${pkg.version}`
);
expect(honey._builder._fields["service_name"]).toBe("unknown_service:nodejs");
expect(honey._builder._fields["service.name"]).toBe("unknown_service:nodejs");
});

test("libhoney default config - non-classic", () => {
api._resetForTesting();
api.configure({
impl: "libhoney-event",
transmission: "mock",
writeKey: "d68f9ed1e96432ac1a3380",
});

const honey = api._apiForTesting().honey;
expect(honey.transmission.constructorArg.apiHost).toBe("https://api.honeycomb.io");
expect(honey.transmission.constructorArg.dataset).toBe("unknown_service");
expect(honey.transmission.constructorArg.writeKey).toBe("d68f9ed1e96432ac1a3380");
expect(honey.transmission.constructorArg.userAgentAddition).toBe(
`honeycomb-beeline/${pkg.version}`
);
expect(honey._builder._fields["service_name"]).toBe("unknown_service:nodejs");
expect(honey._builder._fields["service.name"]).toBe("unknown_service:nodejs");
});

test("libhoney config - non-classic - empty service name", () => {
api._resetForTesting();
api.configure({
impl: "libhoney-event",
transmission: "mock",
writeKey: "d68f9ed1e96432ac1a3380",
serviceName: "",
});

const honey = api._apiForTesting().honey;
expect(honey.transmission.constructorArg.apiHost).toBe("https://api.honeycomb.io");
expect(honey.transmission.constructorArg.dataset).toBe("unknown_service");
expect(honey.transmission.constructorArg.writeKey).toBe("d68f9ed1e96432ac1a3380");
expect(honey.transmission.constructorArg.userAgentAddition).toBe(
`honeycomb-beeline/${pkg.version}`
);
expect(honey._builder._fields["service_name"]).toBe("unknown_service:nodejs");
expect(honey._builder._fields["service.name"]).toBe("unknown_service:nodejs");
});

test("libhoney config - non-classic - whitespace service name", () => {
api._resetForTesting();
api.configure({
impl: "libhoney-event",
transmission: "mock",
writeKey: "d68f9ed1e96432ac1a3380",
serviceName: " "
});

const honey = api._apiForTesting().honey;
expect(honey.transmission.constructorArg.apiHost).toBe("https://api.honeycomb.io");
expect(honey.transmission.constructorArg.dataset).toBe("unknown_service");
expect(honey.transmission.constructorArg.writeKey).toBe("d68f9ed1e96432ac1a3380");
expect(honey.transmission.constructorArg.userAgentAddition).toBe(
`honeycomb-beeline/${pkg.version}`
);
console.log(honey._builder._fields["service_name"]);
expect(honey._builder._fields["service_name"]).toBe(" ");
expect(honey._builder._fields["service.name"]).toBe(" ");
});

test("libhoney config - non-classic - custom service name", () => {
api._resetForTesting();
api.configure({
impl: "libhoney-event",
transmission: "mock",
writeKey: "d68f9ed1e96432ac1a3380",
serviceName: " my-service ",
});

const honey = api._apiForTesting().honey;
expect(honey.transmission.constructorArg.apiHost).toBe("https://api.honeycomb.io");
expect(honey.transmission.constructorArg.dataset).toBe("my-service");
expect(honey.transmission.constructorArg.writeKey).toBe("d68f9ed1e96432ac1a3380");
expect(honey.transmission.constructorArg.userAgentAddition).toBe(
`honeycomb-beeline/${pkg.version}`
);
expect(honey._builder._fields["service_name"]).toBe(" my-service ");
expect(honey._builder._fields["service.name"]).toBe(" my-service ");
});

test("startTrace starts tracking and creates an initial event, finishTrace sends it", () => {
Expand Down
37 changes: 35 additions & 2 deletions lib/api/libhoney.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const libhoney = require("libhoney"),
schema = require("../schema"),
Span = require("./span"),
pkg = require("../../package.json"),
debug = require("debug")(`${pkg.name}:event`);
debug = require("debug")(`${pkg.name}:event`),
util = require("../util");

const defaultName = "nodejs";

Expand Down Expand Up @@ -81,7 +82,38 @@ module.exports = class LibhoneyEventAPI {
debug(`using proxy ${proxy}`);
}

this.defaultDataset = opts.dataset || process.env["HONEYCOMB_DATASET"] || defaultName;
if (!opts.serviceName) {
opts.serviceName = ["unknown_service", process.name ? process.name.trim() : "nodejs"].join(":");
console.warn(`empty serviceName configuration option - setting service name to '${opts.serviceName}'`);
}

if (!opts.writeKey) {
console.warn("empty writeKey configuration option");
}

if (util.isClassic(opts.writeKey)) {
let dataset = opts.dataset || process.env["HONEYCOMB_DATASET"];
if (!dataset || dataset.trim() === "") {
dataset = defaultName;
console.warn(`empty dataset configuration option - setting to '${dataset}'`);
} else {
dataset = dataset.trim();
}

this.defaultDataset = dataset;
} else {
if (opts.serviceName !== opts.serviceName.trim()) {
console.warn(`service name contains whitespace '${opts.serviceName}'`);
}
// if servicename is empty (whitespace) or starts with "unknown_service", use "unknown_service"
// or use trimmed service name
this.defaultDataset = opts.serviceName.startsWith("unknown_service") || opts.serviceName.trim() === ""
? "unknown_service"
: opts.serviceName.trim();
if (opts.dataset) {
console.warn(`dataset should be empty - sending data to '${this.defaultDataset}'`);
}
}

const libhoneyOpts = getFilteredOptions(opts);

Expand All @@ -105,6 +137,7 @@ module.exports = class LibhoneyEventAPI {
this.honey.add({
[schema.HOSTNAME]: os.hostname(),
[schema.TRACE_SERVICE_NAME]: opts.serviceName,
[schema.TRACE_SERVICE_DOT_NAME]: opts.serviceName,
});
}

Expand Down
13 changes: 11 additions & 2 deletions lib/propagation/honeycomb.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ exports.TRACE_HTTP_HEADER = TRACE_HTTP_HEADER;
const VERSION = "1";
exports.VERSION = VERSION;

let propagateDataset = true;

exports.setPropagateDataset = setPropagateDataset;
function setPropagateDataset(enabled) {
propagateDataset = enabled;
}

// assumes a header of the form:

// VERSION;PAYLOAD
Expand Down Expand Up @@ -38,7 +45,7 @@ function marshalTraceContextv1(context) {
let dataset = context.dataset;

let datasetClause = "";
if (dataset) {
if (propagateDataset && dataset) {
datasetClause = `dataset=${encodeURIComponent(dataset)},`;
}

Expand Down Expand Up @@ -84,7 +91,9 @@ function unmarshalTraceContextv1(payload) {
parentSpanId = v;
break;
case "dataset":
dataset = decodeURIComponent(v);
if (propagateDataset) {
dataset = decodeURIComponent(v);
}
break;
case "context":
contextb64 = v;
Expand Down
16 changes: 15 additions & 1 deletion lib/propagation/honeycomb.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ cases(
);

describe("roundtrip", () => {
test("works", () => {
test("classic", () => {
let contextStr = honeycomb.marshalTraceContext(testContext);
expect(honeycomb.unmarshalTraceContext(contextStr)).toEqual({
traceId: "abcdef123456",
Expand All @@ -93,4 +93,18 @@ describe("roundtrip", () => {
},
});
});

test("non-classic", () => {
honeycomb.setPropagateDataset(false);
let contextStr = honeycomb.marshalTraceContext(testContext);
expect(honeycomb.unmarshalTraceContext(contextStr)).toEqual({
traceId: "abcdef123456",
parentSpanId: "0102030405",
customContext: {
userID: 1,
errorMsg: "failed to sign on",
toRetry: true,
},
});
});
});
1 change: 1 addition & 0 deletions lib/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ exports.TRACE_ID_SOURCE = "trace.trace_id_source";
exports.TRACE_PARENT_ID = "trace.parent_id";
exports.TRACE_SPAN_ID = "trace.span_id";
exports.TRACE_SERVICE_NAME = "service_name";
exports.TRACE_SERVICE_DOT_NAME = "service.name";
exports.TRACE_SPAN_NAME = "name";

// custom context fields will have this prefix
Expand Down
6 changes: 6 additions & 0 deletions lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,9 @@ function captureStackTrace(skipFrames = 0, limitFrames = 10) {
// the +1 here to get rid of the `Error\n` line at the top of the stacktrace.
return frames.slice(1 + skipFrames).join("\n");
}

exports.isClassic = isClassic;

function isClassic(writeKey) {
return !writeKey || writeKey.length == 32;
}

0 comments on commit 5510b37

Please sign in to comment.