Skip to content

Commit 23e2167

Browse files
committed
feat: Added segment synthesizer and provided ability to convert http client otel spans to external http trace segments (#2745)
1 parent f4ec888 commit 23e2167

19 files changed

+434
-46
lines changed

THIRD_PARTY_NOTICES.md

Lines changed: 212 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ code, the source code can be found at [https://github.com/newrelic/node-newrelic
1818
* [@grpc/proto-loader](#grpcproto-loader)
1919
* [@newrelic/security-agent](#newrelicsecurity-agent)
2020
* [@opentelemetry/api](#opentelemetryapi)
21+
* [@opentelemetry/semantic-conventions](#opentelemetrysemantic-conventions)
2122
* [@tyriar/fibonacci-heap](#tyriarfibonacci-heap)
2223
* [concat-stream](#concat-stream)
2324
* [https-proxy-agent](#https-proxy-agent)
@@ -763,6 +764,215 @@ This product includes source derived from [@opentelemetry/api](https://github.co
763764
764765
```
765766

767+
### @opentelemetry/semantic-conventions
768+
769+
This product includes source derived from [@opentelemetry/semantic-conventions](https://github.com/open-telemetry/opentelemetry-js) ([v1.27.0](https://github.com/open-telemetry/opentelemetry-js/tree/v1.27.0)), distributed under the [Apache-2.0 License](https://github.com/open-telemetry/opentelemetry-js/blob/v1.27.0/LICENSE):
770+
771+
```
772+
Apache License
773+
Version 2.0, January 2004
774+
http://www.apache.org/licenses/
775+
776+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
777+
778+
1. Definitions.
779+
780+
"License" shall mean the terms and conditions for use, reproduction,
781+
and distribution as defined by Sections 1 through 9 of this document.
782+
783+
"Licensor" shall mean the copyright owner or entity authorized by
784+
the copyright owner that is granting the License.
785+
786+
"Legal Entity" shall mean the union of the acting entity and all
787+
other entities that control, are controlled by, or are under common
788+
control with that entity. For the purposes of this definition,
789+
"control" means (i) the power, direct or indirect, to cause the
790+
direction or management of such entity, whether by contract or
791+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
792+
outstanding shares, or (iii) beneficial ownership of such entity.
793+
794+
"You" (or "Your") shall mean an individual or Legal Entity
795+
exercising permissions granted by this License.
796+
797+
"Source" form shall mean the preferred form for making modifications,
798+
including but not limited to software source code, documentation
799+
source, and configuration files.
800+
801+
"Object" form shall mean any form resulting from mechanical
802+
transformation or translation of a Source form, including but
803+
not limited to compiled object code, generated documentation,
804+
and conversions to other media types.
805+
806+
"Work" shall mean the work of authorship, whether in Source or
807+
Object form, made available under the License, as indicated by a
808+
copyright notice that is included in or attached to the work
809+
(an example is provided in the Appendix below).
810+
811+
"Derivative Works" shall mean any work, whether in Source or Object
812+
form, that is based on (or derived from) the Work and for which the
813+
editorial revisions, annotations, elaborations, or other modifications
814+
represent, as a whole, an original work of authorship. For the purposes
815+
of this License, Derivative Works shall not include works that remain
816+
separable from, or merely link (or bind by name) to the interfaces of,
817+
the Work and Derivative Works thereof.
818+
819+
"Contribution" shall mean any work of authorship, including
820+
the original version of the Work and any modifications or additions
821+
to that Work or Derivative Works thereof, that is intentionally
822+
submitted to Licensor for inclusion in the Work by the copyright owner
823+
or by an individual or Legal Entity authorized to submit on behalf of
824+
the copyright owner. For the purposes of this definition, "submitted"
825+
means any form of electronic, verbal, or written communication sent
826+
to the Licensor or its representatives, including but not limited to
827+
communication on electronic mailing lists, source code control systems,
828+
and issue tracking systems that are managed by, or on behalf of, the
829+
Licensor for the purpose of discussing and improving the Work, but
830+
excluding communication that is conspicuously marked or otherwise
831+
designated in writing by the copyright owner as "Not a Contribution."
832+
833+
"Contributor" shall mean Licensor and any individual or Legal Entity
834+
on behalf of whom a Contribution has been received by Licensor and
835+
subsequently incorporated within the Work.
836+
837+
2. Grant of Copyright License. Subject to the terms and conditions of
838+
this License, each Contributor hereby grants to You a perpetual,
839+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
840+
copyright license to reproduce, prepare Derivative Works of,
841+
publicly display, publicly perform, sublicense, and distribute the
842+
Work and such Derivative Works in Source or Object form.
843+
844+
3. Grant of Patent License. Subject to the terms and conditions of
845+
this License, each Contributor hereby grants to You a perpetual,
846+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
847+
(except as stated in this section) patent license to make, have made,
848+
use, offer to sell, sell, import, and otherwise transfer the Work,
849+
where such license applies only to those patent claims licensable
850+
by such Contributor that are necessarily infringed by their
851+
Contribution(s) alone or by combination of their Contribution(s)
852+
with the Work to which such Contribution(s) was submitted. If You
853+
institute patent litigation against any entity (including a
854+
cross-claim or counterclaim in a lawsuit) alleging that the Work
855+
or a Contribution incorporated within the Work constitutes direct
856+
or contributory patent infringement, then any patent licenses
857+
granted to You under this License for that Work shall terminate
858+
as of the date such litigation is filed.
859+
860+
4. Redistribution. You may reproduce and distribute copies of the
861+
Work or Derivative Works thereof in any medium, with or without
862+
modifications, and in Source or Object form, provided that You
863+
meet the following conditions:
864+
865+
(a) You must give any other recipients of the Work or
866+
Derivative Works a copy of this License; and
867+
868+
(b) You must cause any modified files to carry prominent notices
869+
stating that You changed the files; and
870+
871+
(c) You must retain, in the Source form of any Derivative Works
872+
that You distribute, all copyright, patent, trademark, and
873+
attribution notices from the Source form of the Work,
874+
excluding those notices that do not pertain to any part of
875+
the Derivative Works; and
876+
877+
(d) If the Work includes a "NOTICE" text file as part of its
878+
distribution, then any Derivative Works that You distribute must
879+
include a readable copy of the attribution notices contained
880+
within such NOTICE file, excluding those notices that do not
881+
pertain to any part of the Derivative Works, in at least one
882+
of the following places: within a NOTICE text file distributed
883+
as part of the Derivative Works; within the Source form or
884+
documentation, if provided along with the Derivative Works; or,
885+
within a display generated by the Derivative Works, if and
886+
wherever such third-party notices normally appear. The contents
887+
of the NOTICE file are for informational purposes only and
888+
do not modify the License. You may add Your own attribution
889+
notices within Derivative Works that You distribute, alongside
890+
or as an addendum to the NOTICE text from the Work, provided
891+
that such additional attribution notices cannot be construed
892+
as modifying the License.
893+
894+
You may add Your own copyright statement to Your modifications and
895+
may provide additional or different license terms and conditions
896+
for use, reproduction, or distribution of Your modifications, or
897+
for any such Derivative Works as a whole, provided Your use,
898+
reproduction, and distribution of the Work otherwise complies with
899+
the conditions stated in this License.
900+
901+
5. Submission of Contributions. Unless You explicitly state otherwise,
902+
any Contribution intentionally submitted for inclusion in the Work
903+
by You to the Licensor shall be under the terms and conditions of
904+
this License, without any additional terms or conditions.
905+
Notwithstanding the above, nothing herein shall supersede or modify
906+
the terms of any separate license agreement you may have executed
907+
with Licensor regarding such Contributions.
908+
909+
6. Trademarks. This License does not grant permission to use the trade
910+
names, trademarks, service marks, or product names of the Licensor,
911+
except as required for reasonable and customary use in describing the
912+
origin of the Work and reproducing the content of the NOTICE file.
913+
914+
7. Disclaimer of Warranty. Unless required by applicable law or
915+
agreed to in writing, Licensor provides the Work (and each
916+
Contributor provides its Contributions) on an "AS IS" BASIS,
917+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
918+
implied, including, without limitation, any warranties or conditions
919+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
920+
PARTICULAR PURPOSE. You are solely responsible for determining the
921+
appropriateness of using or redistributing the Work and assume any
922+
risks associated with Your exercise of permissions under this License.
923+
924+
8. Limitation of Liability. In no event and under no legal theory,
925+
whether in tort (including negligence), contract, or otherwise,
926+
unless required by applicable law (such as deliberate and grossly
927+
negligent acts) or agreed to in writing, shall any Contributor be
928+
liable to You for damages, including any direct, indirect, special,
929+
incidental, or consequential damages of any character arising as a
930+
result of this License or out of the use or inability to use the
931+
Work (including but not limited to damages for loss of goodwill,
932+
work stoppage, computer failure or malfunction, or any and all
933+
other commercial damages or losses), even if such Contributor
934+
has been advised of the possibility of such damages.
935+
936+
9. Accepting Warranty or Additional Liability. While redistributing
937+
the Work or Derivative Works thereof, You may choose to offer,
938+
and charge a fee for, acceptance of support, warranty, indemnity,
939+
or other liability obligations and/or rights consistent with this
940+
License. However, in accepting such obligations, You may act only
941+
on Your own behalf and on Your sole responsibility, not on behalf
942+
of any other Contributor, and only if You agree to indemnify,
943+
defend, and hold each Contributor harmless for any liability
944+
incurred by, or claims asserted against, such Contributor by reason
945+
of your accepting any such warranty or additional liability.
946+
947+
END OF TERMS AND CONDITIONS
948+
949+
APPENDIX: How to apply the Apache License to your work.
950+
951+
To apply the Apache License to your work, attach the following
952+
boilerplate notice, with the fields enclosed by brackets "[]"
953+
replaced with your own identifying information. (Don't include
954+
the brackets!) The text should be enclosed in the appropriate
955+
comment syntax for the file format. We also recommend that a
956+
file or class name and description of purpose be included on the
957+
same "printed page" as the copyright notice for easier
958+
identification within third-party archives.
959+
960+
Copyright [yyyy] [name of copyright owner]
961+
962+
Licensed under the Apache License, Version 2.0 (the "License");
963+
you may not use this file except in compliance with the License.
964+
You may obtain a copy of the License at
965+
966+
http://www.apache.org/licenses/LICENSE-2.0
967+
968+
Unless required by applicable law or agreed to in writing, software
969+
distributed under the License is distributed on an "AS IS" BASIS,
970+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
971+
See the License for the specific language governing permissions and
972+
limitations under the License.
973+
974+
```
975+
766976
### @tyriar/fibonacci-heap
767977

768978
This product includes source derived from [@tyriar/fibonacci-heap](https://github.com/gwtw/ts-fibonacci-heap) ([v2.0.9](https://github.com/gwtw/ts-fibonacci-heap/tree/v2.0.9)), distributed under the [MIT License](https://github.com/gwtw/ts-fibonacci-heap/blob/v2.0.9/LICENSE):
@@ -825,7 +1035,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8251035

8261036
### https-proxy-agent
8271037

828-
This product includes source derived from [https-proxy-agent](https://github.com/TooTallNate/proxy-agents) ([v7.0.5](https://github.com/TooTallNate/proxy-agents/tree/v7.0.5)), distributed under the [MIT License](https://github.com/TooTallNate/proxy-agents/blob/v7.0.5/LICENSE):
1038+
This product includes source derived from [https-proxy-agent](https://github.com/TooTallNate/proxy-agents) ([v7.0.4](https://github.com/TooTallNate/proxy-agents/tree/v7.0.4)), distributed under the [MIT License](https://github.com/TooTallNate/proxy-agents/blob/v7.0.4/LICENSE):
8291039

8301040
```
8311041
(The MIT License)
@@ -1228,7 +1438,7 @@ SOFTWARE.
12281438

12291439
### semver
12301440

1231-
This product includes source derived from [semver](https://github.com/npm/node-semver) ([v7.6.3](https://github.com/npm/node-semver/tree/v7.6.3)), distributed under the [ISC License](https://github.com/npm/node-semver/blob/v7.6.3/LICENSE):
1441+
This product includes source derived from [semver](https://github.com/npm/node-semver) ([v7.6.2](https://github.com/npm/node-semver/tree/v7.6.2)), distributed under the [ISC License](https://github.com/npm/node-semver/blob/v7.6.2/LICENSE):
12321442

12331443
```
12341444
The ISC License

lib/metrics/recorders/database.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ function recordQueryMetrics(segment, scope, transaction) {
6161

6262
if (this.raw) {
6363
transaction.agent.queries.add({
64-
segment,
64+
segment,
6565
transaction,
66-
type: this.type.toLowerCase(),
67-
query: this.raw,
66+
type: this.type.toLowerCase(),
67+
query: this.raw,
6868
trace: this.trace
6969
})
7070
}

lib/otel/rules.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class Rule {
4949
#name
5050
#spanKinds
5151
#requiredAttributes
52+
#type
5253
#mappings
5354

5455
/**
@@ -63,6 +64,7 @@ class Rule {
6364
}
6465

6566
this.#name = input.name
67+
this.#type = input.type
6668
this.#spanKinds = input.matcher.required_span_kinds?.map((v) => v.toLowerCase()) ?? []
6769
this.#requiredAttributes = input.matcher.required_attribute_keys ?? []
6870
this.#mappings = input.target.attribute_mappings ?? []
@@ -72,6 +74,10 @@ class Rule {
7274
return this.#name
7375
}
7476

77+
get type() {
78+
return this.#type
79+
}
80+
7581
get isServerRule() {
7682
return this.#spanKinds.includes(Rule.OTEL_SPAN_KIND_SERVER)
7783
}

lib/otel/rules.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@
229229
},
230230
{
231231
"name": "OtelDbClientRedis1_24",
232+
"type": "db",
232233
"matcher": {
233234
"required_span_kinds": [
234235
"client"
@@ -267,6 +268,7 @@
267268
},
268269
{
269270
"name": "OtelDbClient1_24",
271+
"type": "db",
270272
"matcher": {
271273
"required_span_kinds": [
272274
"client"
@@ -302,6 +304,7 @@
302304
},
303305
{
304306
"name": "OtelHttpClient1_23",
307+
"type": "external",
305308
"matcher": {
306309
"required_metric_names": [
307310
"http.client.request.duration"
@@ -338,6 +341,7 @@
338341
},
339342
{
340343
"name": "OtelHttpClient1_20",
344+
"type": "external",
341345
"matcher": {
342346
"required_metric_names": [
343347
"http.client.duration"
@@ -410,6 +414,7 @@
410414
},
411415
{
412416
"name": "FallbackClient",
417+
"type": "external",
413418
"matcher": {
414419
"required_metric_names": [
415420
"rpc.client.duration",

lib/otel/segment-synthesis.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2024 New Relic Corporation. All rights reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
'use strict'
7+
const { RulesEngine } = require('./rules')
8+
const defaultLogger = require('../logger').child({ component: 'segment-synthesizer' })
9+
const NAMES = require('../metrics/names')
10+
const { SEMATTRS_HTTP_HOST } = require('@opentelemetry/semantic-conventions')
11+
12+
class SegmentSynthesizer {
13+
constructor(agent, { logger = defaultLogger } = {}) {
14+
this.agent = agent
15+
this.logger = logger
16+
this.engine = new RulesEngine()
17+
}
18+
19+
synthesize(otelSpan) {
20+
const rule = this.engine.test(otelSpan)
21+
if (!rule?.type) {
22+
this.logger.debug(
23+
'Cannot match a rule to span name: %s, kind %s',
24+
otelSpan?.name,
25+
otelSpan?.kind
26+
)
27+
return
28+
}
29+
30+
if (rule?.type === 'external') {
31+
return this.createExternalSegment(otelSpan)
32+
}
33+
this.logger.debug('Found type: %s, no synthesize rule currently built', rule.type)
34+
}
35+
36+
// TODO: should we move these to somewhere else and use in the places
37+
// where external segments are created in our agent
38+
createExternalSegment(otelSpan) {
39+
const context = this.agent.tracer.getContext()
40+
const host = otelSpan.attributes[SEMATTRS_HTTP_HOST] || 'Unknown'
41+
const name = NAMES.EXTERNAL.PREFIX + host
42+
return this.agent.tracer.createSegment({
43+
name,
44+
parent: context.segment,
45+
transaction: context.transaction
46+
})
47+
}
48+
}
49+
50+
module.exports = SegmentSynthesizer

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@
198198
"@grpc/proto-loader": "^0.7.5",
199199
"@newrelic/security-agent": "^2.0.0",
200200
"@opentelemetry/api": "^1.9.0",
201+
"@opentelemetry/semantic-conventions": "^1.27.0",
201202
"@tyriar/fibonacci-heap": "^2.0.7",
202203
"concat-stream": "^2.0.0",
203204
"https-proxy-agent": "^7.0.1",

test/integration/core/crypto.test.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ test('pbkdf2', function (t, end) {
2626
crypto.pbkdf2('hunter2', 'saltine', 5, 32, 'sha1', function (err, key) {
2727
assert.ok(!err, 'should not error')
2828
assert.equal(key.length, 32)
29-
debugger
3029
verifySegments({ agent, end, name: 'crypto.pbkdf2' })
3130
})
3231
})

test/integration/core/fs.test.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,6 @@ test('read', async function (t) {
854854
plan.equal(agent.getTransaction(), trans, 'should preserve transaction')
855855
const children = trans.trace.getChildren(trans.trace.root.id)
856856
plan.equal(children.length, 0, 'should not create any segments')
857-
858857
})
859858
})
860859

0 commit comments

Comments
 (0)