Skip to content
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(exporters)!: collapse base classes into one #5031

Merged

Conversation

pichlermarc
Copy link
Member

@pichlermarc pichlermarc commented Oct 2, 2024

Which problem is this PR solving?

Through recent changes I've been working on reducing code-duplication across the exporters and separating config-code, transport code and base exporter code. I'm doing this for three reasons:

  • improve how well we can test parts of the exporter
  • address some design-level bugs that we've introduced over the year
  • reduce the public API to maintainable levels

In the changes I made previously, we have seen a convergence of the OTLPExporterNodeBase, OTLPExporterBrowserBase, and OTLPGRPCExporterBase classes. This PR removes all of these classes, and replaces them with an implementation of a new interface: IOTLPExportDelegate

Collapsing these into a single implementation with a single name has the benefit of fixing #4794, which was caused by differently named platform exports for Node.js and the Browser - a design-level bug that needed resolving before we can consider an OTLP Exporter GA release. I'm fixing the problem of having different public interfaces for different transports by introducing new entrypoints: node-http and browser-http which are only imported by their respective platform-specific implementations.

This export delegate contains all the behavior that is present in the OTLP exporter specification and shared across all signals. It can be created via a factory function to avoid exposing the internal API as public. Specific exporters are expected to use this delegate to eventually compose an exporter though different transports and serializers. Composition is used over inheritance as polymorphism is not of relevance when using an OTLP exporter: It is either a PushMetricExporter, a SpanExporter, or a LogRecordExporter - having an OTLPExporterBase does not add any value to the end-user as the public interface ends up being the same. On top of that it was only used internally as it was the easy way of getting base functionality to the individual exporters. In doing so it also exposed a lot of internals as part of the public API.

OTLPExporterBase still exists but now only takes an IOTLPExportDelegate and will eventually be removed. I've decided to keep it around to have a base for the individual exporters, which can be instantiated with new. In a future revision, I plan to introduce factory functions for each exporter which returns a PushMetricExporter, a SpanExporter, or a LogRecordExporter instead of a specific exporter class. The factory functions will also do away with some duplicate ways of configuring transports.

As a way to transition to these factory functions, this PR introduces "translation" helpers for the "old" configuration to the "new" one which is already used internally (these legacy conversions can be identified by the word legacy in their names).

Fixes #4794
Updates #4186

Breaking changes

  • feat(otlp-exporter-base)!: collapse base classes into one
    • OTLPExporterNodeBase has been removed in favor of a platform-agnostic implementation (OTLPExporterBase)
    • OTLPExporterBrowserBase has been removed in favor of a platform-agnostic implementation (OTLPExporterBase)
    • ExportServiceError was intended for internal use and has been dropped from exports
    • validateAndNormalizeHeaders was intended for internal use and has been dropped from exports
    • OTLPExporterBase all properties are now private, the constructor now takes an IOTLPExportDelegate, the type parameter for config type has been dropped.
      • This type is scheduled for removal in a future version of this package, please treat all exporters as SpanExporter, PushMetricExporter or LogRecordExporter, based on their respective type.
  • feat(otlp-grpc-exporter-base)!: collapse base classes into one
    • OTLPGRPCExporterNodeBase has been removed in favor of a platform-agnostic implementation (OTLPExporterBase from @opentelemetry/otlp-exporter-base)

Type of change

Please delete options that are not relevant.

  • Bug fix
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

How Has This Been Tested?

  • Added unit tests, adapted existing tests

Copy link

codecov bot commented Oct 2, 2024

Codecov Report

Attention: Patch coverage is 98.46154% with 2 lines in your changes missing coverage. Please review.

Project coverage is 94.56%. Comparing base (1370810) to head (c986148).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...-exporter-base/src/otlp-network-export-delegate.ts 60.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5031      +/-   ##
==========================================
+ Coverage   93.19%   94.56%   +1.37%     
==========================================
  Files         314      314              
  Lines        8077     7961     -116     
  Branches     1622     1600      -22     
==========================================
+ Hits         7527     7528       +1     
+ Misses        550      433     -117     
Files with missing lines Coverage Δ
...ges/exporter-logs-otlp-grpc/src/OTLPLogExporter.ts 100.00% <100.00%> (ø)
...ogs-otlp-http/src/platform/node/OTLPLogExporter.ts 100.00% <100.00%> (ø)
...gs-otlp-proto/src/platform/node/OTLPLogExporter.ts 100.00% <100.00%> (ø)
.../exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts 100.00% <100.00%> (ø)
...e-otlp-http/src/platform/node/OTLPTraceExporter.ts 100.00% <100.00%> (ø)
...-otlp-proto/src/platform/node/OTLPTraceExporter.ts 100.00% <100.00%> (ø)
...porter-metrics-otlp-grpc/src/OTLPMetricExporter.ts 100.00% <100.00%> (ø)
...er-metrics-otlp-http/src/OTLPMetricExporterBase.ts 89.85% <100.00%> (+5.79%) ⬆️
...-otlp-http/src/platform/node/OTLPMetricExporter.ts 100.00% <100.00%> (ø)
...orter-metrics-otlp-proto/src/OTLPMetricExporter.ts 100.00% <100.00%> (ø)
... and 14 more

... and 2 files with indirect coverage changes

---- 🚨 Try these New Features:

Copy link
Contributor

@david-luna david-luna left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR looks good :) but I wonder about convertLegacyOtlpGrpcOptions and other functions with legacy in its name. If the PR is already breaking why not refactor the interfaces so we do not need any transformation function from legacy options?

* TODO: Replace export * with named exports before next major version
*/
export * from './node';
export { OTLPMetricExporter } from './node';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why exporting only the class from ./node?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep that's somewhat confusing but it's how all our platform-specific exports work, see here. 🙂

The way I understand it, when bundled for the the browser, webpack overrides all usages of this file with the one from platform/browser/index.js - so the user will end up with the correct implementation.

AFAIK we can't override the other way around so that's what ended up becoming the default.

@pichlermarc
Copy link
Member Author

pichlermarc commented Nov 14, 2024

PR looks good :) but I wonder about convertLegacyOtlpGrpcOptions and other functions with legacy in its name. If the PR is already breaking why not refactor the interfaces so we do not need any transformation function from legacy options?

Yes, good point - the PR is already breaking but I'm trying to make it so that anyone using the exporter in a "normal" way (i.e. not extending it, just using the constructor and then passing it to a MetricReader/SpanProcessor/LogRecordProcessor) is not broken in the process. It's actually something that I've been paying attention to throughout the process of re-writing the exporters. That's why I'm keeping the legacy options around. 🙂

I'm then planning to introduce a new factory function for each exporter that will eventually replace the constructors, so that we don't have to export a class directly anymore, but we can have the factory function return a PushMetricExporter/SpanExporter/LogRecordExporter instead. These factory functions will then take the "new" options while we deprecate and phase out the constructor and the "old" options - which I'm planning to remove in 2.0 (if timelines permit 😅)

@pichlermarc pichlermarc added this pull request to the merge queue Nov 19, 2024
Merged via the queue into open-telemetry:main with commit 7e98761 Nov 19, 2024
21 checks passed
@pichlermarc pichlermarc deleted the feat/use-export-delegate branch November 19, 2024 13:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Wrong import for "OTLPExporterNodeBase"
2 participants