-
Notifications
You must be signed in to change notification settings - Fork 789
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(opentelemetry-resources): add schema url #5070
base: main
Are you sure you want to change the base?
Changes from 2 commits
cbfc6af
ab3f9c6
46148a6
23f8584
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -35,6 +35,7 @@ export class Resource implements IResource { | |||||||
private _syncAttributes?: ResourceAttributes; | ||||||||
private _asyncAttributesPromise?: Promise<ResourceAttributes>; | ||||||||
private _attributes?: ResourceAttributes; | ||||||||
private _schemaUrl?: string; // Added schemaUrl property | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
/** | ||||||||
* Check if async attributes have resolved. This is useful to avoid awaiting | ||||||||
|
@@ -67,13 +68,9 @@ export class Resource implements IResource { | |||||||
} | ||||||||
|
||||||||
constructor( | ||||||||
/** | ||||||||
* A dictionary of attributes with string keys and values that provide | ||||||||
* information about the entity as numbers, strings or booleans | ||||||||
* TODO: Consider to add check/validation on attributes. | ||||||||
*/ | ||||||||
attributes: ResourceAttributes, | ||||||||
asyncAttributesPromise?: Promise<ResourceAttributes> | ||||||||
asyncAttributesPromise?: Promise<ResourceAttributes>, | ||||||||
schemaUrl: string = '' // Added schemaUrl parameter | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
) { | ||||||||
this._attributes = attributes; | ||||||||
this.asyncAttributesPending = asyncAttributesPromise != null; | ||||||||
|
@@ -90,6 +87,7 @@ export class Resource implements IResource { | |||||||
return {}; | ||||||||
} | ||||||||
); | ||||||||
this._schemaUrl = schemaUrl; // Store the schemaUrl | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
} | ||||||||
|
||||||||
get attributes(): ResourceAttributes { | ||||||||
|
@@ -102,6 +100,13 @@ export class Resource implements IResource { | |||||||
return this._attributes ?? {}; | ||||||||
} | ||||||||
|
||||||||
/** | ||||||||
* Returns the schema URL of the resource. | ||||||||
*/ | ||||||||
public getSchemaUrl(): string { | ||||||||
return this._schemaUrl || ''; // Return schema URL as string | ||||||||
} | ||||||||
|
||||||||
/** | ||||||||
* Returns a promise that will never be rejected. Resolves when all async attributes have finished being added to | ||||||||
* this Resource's attributes. This is useful in exporters to block until resource detection | ||||||||
|
@@ -127,15 +132,18 @@ export class Resource implements IResource { | |||||||
// SpanAttributes from other resource overwrite attributes from this resource. | ||||||||
const mergedSyncAttributes = { | ||||||||
...this._syncAttributes, | ||||||||
//Support for old resource implementation where _syncAttributes is not defined | ||||||||
// Support for old resource implementation where _syncAttributes is not defined | ||||||||
...((other as Resource)._syncAttributes ?? other.attributes), | ||||||||
}; | ||||||||
|
||||||||
// Merge schema URLs, handling conflicts | ||||||||
const mergedSchemaUrl = this._mergeSchemaUrls(this._schemaUrl || '', (other as Resource)._schemaUrl || ''); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think since
Suggested change
and we can get rid of the back-cast. 🙂 |
||||||||
|
||||||||
if ( | ||||||||
!this._asyncAttributesPromise && | ||||||||
!(other as Resource)._asyncAttributesPromise | ||||||||
) { | ||||||||
return new Resource(mergedSyncAttributes); | ||||||||
return new Resource(mergedSyncAttributes, undefined, mergedSchemaUrl); | ||||||||
} | ||||||||
|
||||||||
const mergedAttributesPromise = Promise.all([ | ||||||||
|
@@ -145,12 +153,26 @@ export class Resource implements IResource { | |||||||
return { | ||||||||
...this._syncAttributes, | ||||||||
...thisAsyncAttributes, | ||||||||
//Support for old resource implementation where _syncAttributes is not defined | ||||||||
// Support for old resource implementation where _syncAttributes is not defined | ||||||||
...((other as Resource)._syncAttributes ?? other.attributes), | ||||||||
...otherAsyncAttributes, | ||||||||
}; | ||||||||
}); | ||||||||
|
||||||||
return new Resource(mergedSyncAttributes, mergedAttributesPromise); | ||||||||
return new Resource(mergedSyncAttributes, mergedAttributesPromise, mergedSchemaUrl); | ||||||||
} | ||||||||
|
||||||||
/** | ||||||||
* Helper function to merge schema URLs. If both schema URLs are present and differ, | ||||||||
* a warning is logged and the first schema URL is prioritized. | ||||||||
*/ | ||||||||
private _mergeSchemaUrls( | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this would be better as a stand-alone utility function as it does not access anything on the instance. |
||||||||
schemaUrl1: string, | ||||||||
schemaUrl2: string | ||||||||
): string { | ||||||||
if (schemaUrl1 && schemaUrl2 && schemaUrl1 !== schemaUrl2) { | ||||||||
diag.warn('Schema URLs differ. Using the original schema URL.'); | ||||||||
} | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. here we've already established that schema URL is a string (not undefined or null) though the type-system - why add null-checks? 🤔 |
||||||||
return schemaUrl1 || schemaUrl2; // Return merged schema URL as string | ||||||||
} | ||||||||
} | ||||||||
} | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing newline 🙂
Suggested change
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -330,7 +330,7 @@ describe('Resource', () => { | |||||||||||||||||||||
const resource = Resource.EMPTY; | ||||||||||||||||||||||
const oldResource = new Resource190({ fromold: 'fromold' }); | ||||||||||||||||||||||
|
||||||||||||||||||||||
const mergedResource = resource.merge(oldResource); | ||||||||||||||||||||||
const mergedResource = resource.merge(oldResource as any); | ||||||||||||||||||||||
|
||||||||||||||||||||||
assert.strictEqual(mergedResource.attributes['fromold'], 'fromold'); | ||||||||||||||||||||||
}); | ||||||||||||||||||||||
|
@@ -342,11 +342,63 @@ describe('Resource', () => { | |||||||||||||||||||||
); | ||||||||||||||||||||||
const oldResource = new Resource190({ fromold: 'fromold' }); | ||||||||||||||||||||||
|
||||||||||||||||||||||
const mergedResource = resource.merge(oldResource); | ||||||||||||||||||||||
const mergedResource = resource.merge(oldResource as any); | ||||||||||||||||||||||
assert.strictEqual(mergedResource.attributes['fromold'], 'fromold'); | ||||||||||||||||||||||
|
||||||||||||||||||||||
await mergedResource.waitForAsyncAttributes?.(); | ||||||||||||||||||||||
assert.strictEqual(mergedResource.attributes['fromnew'], 'fromnew'); | ||||||||||||||||||||||
}); | ||||||||||||||||||||||
}); | ||||||||||||||||||||||
|
||||||||||||||||||||||
it('should initialize resource with schema URL', () => { | ||||||||||||||||||||||
const schemaUrl = 'https://example.com/schema'; | ||||||||||||||||||||||
const resource = new Resource( | ||||||||||||||||||||||
{ 'k8s.io/container/name': 'c1' }, | ||||||||||||||||||||||
undefined, | ||||||||||||||||||||||
schemaUrl | ||||||||||||||||||||||
); | ||||||||||||||||||||||
assert.strictEqual(resource.getSchemaUrl(), schemaUrl); | ||||||||||||||||||||||
}); | ||||||||||||||||||||||
|
||||||||||||||||||||||
it('should merge resources with different schema URLs', () => { | ||||||||||||||||||||||
const schemaUrl1 = 'https://example.com/schema1'; | ||||||||||||||||||||||
const schemaUrl2 = 'https://example.com/schema2'; | ||||||||||||||||||||||
const resource1 = new Resource({ 'attr1': 'value1' }, undefined, schemaUrl1); | ||||||||||||||||||||||
const resource2 = new Resource({ 'attr2': 'value2' }, undefined, schemaUrl2); | ||||||||||||||||||||||
|
||||||||||||||||||||||
const debugStub = sinon.spy(diag, 'warn'); | ||||||||||||||||||||||
const mergedResource = resource1.merge(resource2); | ||||||||||||||||||||||
|
||||||||||||||||||||||
assert.strictEqual(mergedResource.getSchemaUrl(), schemaUrl1); | ||||||||||||||||||||||
assert.ok(debugStub.calledWithMatch('Schema URLs differ. Using the original schema URL.')); | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||
}); | ||||||||||||||||||||||
|
||||||||||||||||||||||
it('should retain the same schema URL when merging resources with identical URLs', () => { | ||||||||||||||||||||||
const schemaUrl = 'https://example.com/schema'; | ||||||||||||||||||||||
const resource1 = new Resource({ 'attr1': 'value1' }, undefined, schemaUrl); | ||||||||||||||||||||||
const resource2 = new Resource({ 'attr2': 'value2' }, undefined, schemaUrl); | ||||||||||||||||||||||
|
||||||||||||||||||||||
const mergedResource = resource1.merge(resource2); | ||||||||||||||||||||||
|
||||||||||||||||||||||
assert.strictEqual(mergedResource.getSchemaUrl(), schemaUrl); | ||||||||||||||||||||||
}); | ||||||||||||||||||||||
|
||||||||||||||||||||||
it('should retain schema URL from the resource that has it when merging', () => { | ||||||||||||||||||||||
const resource1 = new Resource({ 'attr1': 'value1' }, undefined, ''); | ||||||||||||||||||||||
const resource2 = new Resource({ 'attr2': 'value2' }, undefined, 'https://example.com/schema'); | ||||||||||||||||||||||
|
||||||||||||||||||||||
const mergedResource = resource1.merge(resource2); | ||||||||||||||||||||||
|
||||||||||||||||||||||
assert.strictEqual(mergedResource.getSchemaUrl(), 'https://example.com/schema'); | ||||||||||||||||||||||
}); | ||||||||||||||||||||||
|
||||||||||||||||||||||
it('should have empty schema URL when merging resources with no schema URL', () => { | ||||||||||||||||||||||
const resource1 = new Resource({ 'attr1': 'value1' }, undefined, ''); | ||||||||||||||||||||||
const resource2 = new Resource({ 'attr2': 'value2' }, undefined, ''); | ||||||||||||||||||||||
|
||||||||||||||||||||||
const mergedResource = resource1.merge(resource2); | ||||||||||||||||||||||
|
||||||||||||||||||||||
assert.strictEqual(mergedResource.getSchemaUrl(), ''); | ||||||||||||||||||||||
}); | ||||||||||||||||||||||
}); | ||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,7 +20,7 @@ import * as assert from 'assert'; | |
// If compilation fails at this point then the changes made are breaking. | ||
class RegressionTestResourceDetector_1_9_1 implements Detector { | ||
async detect(_config?: ResourceDetectionConfig): Promise<Resource> { | ||
return Resource.empty(); | ||
return Resource.empty() as any; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The comment above this detector still holds - if this needs to be modified, the changes in this PR are breaking. |
||
} | ||
} | ||
|
||
|
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 stable interface, we can only add new optional properties here - this is likely why you had to adjust the tests (adding
as Resource
andas any
)