-
Notifications
You must be signed in to change notification settings - Fork 6
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: ✨ Endpoint & API Key config #22
Conversation
serviceName?: string; | ||
|
||
/** The sample rate used to determine whether a trace is exported. Defaults to 1 (send everything). */ | ||
sampleRate?: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is at a trace level, not a session level, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep this is trace level!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tell people what to set it to for something else. I think it's a whole number, "send 1 of every sampleRate traces"
* @param apikey the apikey | ||
* @returns a boolean to indicate if the apikey was a classic key | ||
*/ | ||
export function isClassic(apikey?: string): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just a note, this will soon have a third variation, not sure if you want to go ahead and prepare for that (talk to API&Partnerships for the doc around new key structure)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good point, I was thinking about this and I believe this check still stands because we're checking if a key is Classic or not and Classic keys aren't changing from 32 characters. This would only be affected if any newer keys can be 32 characters which I don't think is the case but I will double check with API&Partnerships on that!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All our code uses this "isClassic" implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added some comments, but feel free to ignore them if I'm missing the point.
src/util.ts
Outdated
* based exporter protocol. | ||
* | ||
* @param url the base URL to append traces path to if missing | ||
* @param protocol the exporter protocol to send telemetry |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this parameter isn't on the function
examples/hello-world-web/index.js
Outdated
|
||
const main = () => { | ||
// Set OTel to log in Debug mode | ||
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG); | ||
|
||
// Initialize base OTel WebSDK | ||
const sdk = new WebSDK({ | ||
const sdk = new HoneycombWebSDK({ | ||
endpoint: 'https://api.honeycomb.io/v1/traces', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you have code below to add /v1/traces
if it's missing, maybe it would be better to leave it off?
* @param protocol the exporter protocol to send telemetry | ||
* @returns the endpoint with traces path appended if missing | ||
*/ | ||
export function maybeAppendTracesPath(url: string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we might have a situation where if they add a trailing slash, it doesn't work. If so, should we check for that?
Also, what about logs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great catch! Updated the logic and I'll make a PR to the Node distro to update it there as well 👍🏽
As for logs, the distro doesn't have a log exporter at the moment so there will be a separate function and exporter for that when we support it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sadly, logs are not considered stable in otel-js yet.
We're going to need them for FEO, but maybe not for RUM
|
||
// classic keys are 32 chars long | ||
const classicApiKey = 'this is a string that is 32 char'; | ||
// non-classic keys are 22 chars log |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
technically, because they're not 0-padded, they can be any length up to 23, IIRC. But we should never depend on it.
Also, classic keys are hex only, while non-classic are alphanumeric.
expect(endpoint).toBe('https://api.honeycomb.io/v1/traces'); | ||
}); | ||
|
||
it('does not append the traces path if the url ends with /v1/traces', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a test for if they give you /v1/traces/
?
Co-authored-by: Kent Quirk <kentquirk@gmail.com>
I don't see any changes Meaning: there's nothing new in the README, so from an external perspective this project is the same 😛 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
url: getTracesEndpoint(options), | ||
headers: { | ||
[TEAM_HEADER_KEY]: apiKey, | ||
[DATASET_HEADER_KEY]: isClassic(apiKey) ? options?.dataset : undefined, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dataset is different from serviceName? we don't fall back to serviceName? We don't fail if it's classic and dataset is unpopulated?
... the send will fail, which is hard to diagnose
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(my surprise will be cured by documentation)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, there's no dataset header needed fpr ingest needed for non-classic. It just uses whatever service.name
is set to, and the backend assigns a dataset for you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cartermp I was thinking that maybe it makes sense to default dataset to service.name in classic? ... but that's probably wrong too, because it would have to be coincidentally correct.
I do think it makes sense to fail when we don't get a dataset header in Classic mode, so we can give them a link to the page that explains it.
src/types.ts
Outdated
/** The API key used to send telemetry to Honeycomb. */ | ||
apiKey?: string; | ||
|
||
/** The API key used to send traces telemetry to Honeycomb. Defaults to apikey if not set. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as opposed to?
... metrics maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, no, I don't see a metrics one. so what is this one for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't support metrics yet but this is there because if/when we do there will also be metricsApiKey
and logsApiKey
src/honeycomb-otel-sdk.ts
Outdated
export class HoneycombWebSDK extends WebSDK { | ||
constructor(options?: HoneycombOptions) { | ||
super({ | ||
spanProcessor: new BatchSpanProcessor( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right here at this line I say, "oh, I'm not gonna use this."
Because I can't override the spanProcessor to send to my local collector when I'm ready to do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm we're going to struggle with this because we want to provide our own BrowserAttributesSpanProcessor
so this can be changed to passing directly to a trace exporter but eventually we'll have to use the spanProcessor attribute
.
I wonder if there's a way we can accept a span processor that we extend with the things we want to add to it 🤔 . For now I'll change this to exporting through the traceExporter
option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, accepting a span processor and wrapping it is a good idea!
dataset?: string; | ||
|
||
/** The service name of the application and where traces telemetry is stored in Honeycomb. */ | ||
serviceName?: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
defaults to "unknown_service"
src/types.ts
Outdated
/** The API endpoint where traces telemetry is sent. Defaults to endpoint if not set. */ | ||
tracesEndpoint?: string; | ||
|
||
/** The dataset where traces telemetry is stored in Honeycomb. Only used when using a classic API key. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and required when using a classic API key, link to https://docs.honeycomb.io/honeycomb-classic/#am-i-using-honeycomb-classic
/** The debug flag enables additional logging that us useful when debugging your application. Do not use in production. */ | ||
debug?: boolean; | ||
|
||
/** The local visualizations flag enables logging Honeycomb URLs for completed traces. Do not use in production. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this one is my FAVORITE
* used in conjuction with an OpenTelemetry Collector (which will handle the API key and dataset configuration). | ||
* Defaults to 'false'. | ||
*/ | ||
skipOptionsValidation?: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if we made an option for "I have a local collector"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this idea, right now all our other distros are structured this way so I think we would have to have a larger conversation about adding that option
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's OK for this distro to be ahead of the others, but it does make sense to talk to the other maintainers about this direction
const honeycomb = new HoneycombWebSDK(); | ||
expect(honeycomb).toBeDefined(); | ||
expect(honeycomb).toBeInstanceOf(WebSDK); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... if you can pass in options of a span processor, then you can pass in a test spanprocessor and do more testing.
(another vote for passing in a span processor)
/** The API endpoint where telemetry is sent. Defaults to 'https://api.honeycomb.io' */ | ||
endpoint?: string; | ||
|
||
/** The API endpoint where traces telemetry is sent. Defaults to endpoint if not set. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It defaults to endpoint/v1/traces !!! That is why you would set this endpoint
| *serviceName* | optional | string|unknown_service | The name of this browser application. Your telemetry will go to a Honeycomb dataset with this name. | | ||
| *localVisualizations*| optional | boolean | false | For each trace created, print a link to the console so that you can find it in Honeycomb. Super useful in development! Do not use in production. | | ||
| sampleRate | optional | number |1 | If you want to send a random fraction of traces, then make this a whole number greater than 1. Only 1 in `sampleRate` traces will be sent, and the rest never be created. | | ||
| tracesEndpoint | optional | string|`${endpoint}/v1/traces` | Populate this to send traces to a route other than /v1/traces | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This actually doesn't append /v1/traces
to an endpoint. This option exists similar to tracesApiKey
for when you want to set different endpoints for different signals.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you don't set tracesEndpoint, then does it send to $endpoint/v1/traces?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... because that's what the regular SDK does
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm so are we saying, we default tracesEndpoint to $endpoint, but then Otel adds /v1/traces under the hood if it's only a domain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic we follow for endpoints is laid out in our distro spec.
This is the order of logic:
- if
tracesEndpoint
is set, use that and do not append/v1/traces
- if
tracesEndpoint
is not set, fall back toendpoint
which will append/v1/traces
- if
endpoint
is not set, default tohttps://api.honeycomb.io
with/v1/traces
appended
We add /v1/traces
to endpoint automatically (OTel doesn't do this under the hood), as long as the
endpointstring doesn't already end in
/v1/traces`.
Merging this for now, will have follow up PRs for tests & collector option |
Which problem is this PR solving?
Short description of the changes
Out of scope(for this PR):
How to verify that this has the expected result