-
Notifications
You must be signed in to change notification settings - Fork 837
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
Converge sync and async resources #5350
base: main
Are you sure you want to change the base?
Converge sync and async resources #5350
Conversation
packages/opentelemetry-resources/test/regression/existing-detectors-1-9-1.test.ts
Outdated
Show resolved
Hide resolved
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.
Thank you for working on this 🙂
A quick preliminary review - I'll have a closer look at the implementation details next week :)
experimental/packages/opentelemetry-browser-detector/test/util.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-resources/src/detectors/BrowserDetector.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-resources/src/detectors/platform/node/OSDetector.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-resources/src/detectors/BrowserDetector.ts
Outdated
Show resolved
Hide resolved
@@ -73,7 +73,7 @@ describe('getMachineId on BSD', () => { | |||
|
|||
const machineId = await getMachineId(); | |||
|
|||
assert.equal(machineId, ''); | |||
assert.equal(machineId, 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.
assert.equal(machineId, undefined); | |
assert.strictEqual(machineId, undefined); |
@@ -80,7 +80,7 @@ describe('getMachineId on Darwin', () => { | |||
|
|||
const machineId = await getMachineId(); | |||
|
|||
assert.equal(machineId, ''); | |||
assert.equal(machineId, 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.
assert.equal(machineId, undefined); | |
assert.strictEqual(machineId, undefined); |
@@ -60,7 +60,7 @@ describe('getMachineId on linux', () => { | |||
|
|||
const machineId = await getMachineId(); | |||
|
|||
assert.equal(machineId, ''); | |||
assert.equal(machineId, 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.
assert.equal(machineId, undefined); | |
assert.strictEqual(machineId, undefined); |
class EnvDetector implements Detector { | ||
class EnvDetector implements ResourceDetector { | ||
// Type, attribute keys, and attribute values should not exceed 256 characters. | ||
private readonly _MAX_LENGTH = 255; |
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.
nit but is there a reason to prefer to have these as private readonly
fields, as opposed to un-exported module-level constant? the latter seems more "truly" private, easier to type, and more mangle/tree-shaking friendly.
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.
no. The implementation was unchanged in this PR but can be fixed in a follow-up. the reason git thinks i changed the impl is because there used to be a different file for the sync detector.
}); | ||
} | ||
|
||
public get asyncAttributesPending() { |
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.
public get asyncAttributesPending() { | |
public get asyncAttributesPending(): boolean { |
return attrs; | ||
} | ||
|
||
public getRawAttributes() { |
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.
public getRawAttributes() { | |
public getRawAttributes(): RawResourceAttribute[] { |
detect(config?: ResourceDetectionConfig): Promise<IResource> { | ||
return Promise.resolve(browserDetectorSync.detect(config)); | ||
class BrowserDetector implements ResourceDetector { | ||
detect(config?: ResourceDetectionConfig) { |
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.
: DetectedResource
...if we want to be consistent about public interface return types, I'd leave a suggestion but this requires adding the import too
/** | ||
* Returns a {@link Resource} populated with attributes from the | ||
* OTEL_RESOURCE_ATTRIBUTES environment variable. Note this is an async | ||
* function to conform to the Detector interface. | ||
* | ||
* @param config The resource detection config | ||
*/ | ||
detect(config?: ResourceDetectionConfig): Promise<IResource> { | ||
return Promise.resolve(envDetectorSync.detect(config)); | ||
detect(_config?: ResourceDetectionConfig) { |
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.
: DetectedResource
...if we want to be consistent about public interface return types, I'd leave a suggestion but this requires adding the import too
detect(): Promise<IResource> { | ||
return Promise.resolve(noopDetectorSync.detect()); | ||
export class NoopDetector implements ResourceDetector { | ||
detect() { |
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.
: DetectedResource
...if we want to be consistent about public interface return types, I'd leave a suggestion but this requires adding the import too
detect(_config?: ResourceDetectionConfig): Promise<IResource> { | ||
return Promise.resolve(osDetectorSync.detect(_config)); | ||
class OSDetector implements ResourceDetector { | ||
detect(_config?: ResourceDetectionConfig) { |
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.
: DetectedResource
...if we want to be consistent about public interface return types, I'd leave a suggestion but this requires adding the import too
detect(config?: ResourceDetectionConfig): Promise<IResource> { | ||
return Promise.resolve(processDetectorSync.detect(config)); | ||
class ProcessDetector implements ResourceDetector { | ||
detect(_config?: ResourceDetectionConfig) { |
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.
: DetectedResource
...if we want to be consistent about public interface return types, I'd leave a suggestion but this requires adding the import too
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.
Take it with an unhealthy amount of salt, but other than the suggestions I left (feel free to make your own judgment call), it looks good to me!
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 this LGTM.
I asked a Q at #5358 (comment)
I'm not totally clear on what the user's experience with resources (usage with the SDK I mean) will be after these changes at #5358, especially when Entities come along.
return Resource.FromAttributeList([ | ||
...resource._rawAttributes, | ||
...this._rawAttributes, | ||
]); |
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.
Might be nice to ahve a comment here that resource
is first here because (a) the implementation is "first one wins" and (b) the spec says:
https://opentelemetry.io/docs/specs/otel/resource/sdk/#merge
If a key exists on both the old and updating resource, the value of the updating resource MUST be picked (even if the updated value is empty).
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'll add a comment, but does this implementation convey intent better to you?
return Resource.FromAttributeList(
[...this.getRawAttributes(), ...resource.getRawAttributes()].reverse()
);
advantages:
- More explicit intent
- reversing both arrays guards against arrays with duplicate entries (unlikely/impossible but /shrug)
disadvantages:
- slightly less efficient
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.
Another possibility would be to change the impl of FromAttributeList
to have the opposite order semantic.
edit: actually the first-wins semantic comes from the attributes
getter, so that's what would have to change.
Fixes: #3582
This PR makes it so that any resource detector can detect sync and async resources, returning both in a single resource object.
attributes
key, which all attributes are nested under. This will make it easier to extend for entities in the future by adding a new key to the object.To be done in follow-up: