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

Allow multiple views per instrument #3541

Merged
merged 6 commits into from
Aug 25, 2021

Conversation

jsuereth
Copy link
Contributor

  • Allow multiple views per instrument
  • Log on view conflict instead of throwing an exception.
  • Update error reporting (slightly)

This does NOT

  • Attempt to only poll async metrics once-per-instrument (instead once-per-metric for now)
  • Give the best error messages

- Split writeable api from readable api for storage
- Create multi-writeable APIs for when multiple views are defined per instrument.
- Add test to ensure multiple metrics can be exported
- Fix minor issues in registry + sdk meter provider limiting multi-view registration.
Copy link
Contributor

@jkwatson jkwatson left a comment

Choose a reason for hiding this comment

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

one little gripe & a corresponding nit, but this looks pretty solid to me.

@jsuereth jsuereth marked this pull request as ready for review August 25, 2021 13:29
@jsuereth jsuereth requested a review from a user August 25, 2021 13:29
@jkwatson jkwatson merged commit b19157e into open-telemetry:main Aug 25, 2021
meterProviderSharedState.getStartEpochNanos(),
metricUpdater));
} catch (DuplicateMetricStorageException e) {
logger.log(Level.WARNING, e, () -> "Failed to register metric.");
Copy link
Member

Choose a reason for hiding this comment

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

#nit: This message isn't expensive to compute so let's omit the supplier. Same applies to the other catch log messages in this class.

Suggested change
logger.log(Level.WARNING, e, () -> "Failed to register metric.");
logger.log(Level.WARNING, "Failed to register metric.", e);

Copy link
Contributor

Choose a reason for hiding this comment

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

@jsuereth something for a follow-on PR

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, the expensive calculation is in a downstream branch. Once I fix the error messages for better provenance we can account for this.

* @return The list of {@link View}s for this instrument in registered order, or a default
* aggregation view.
*/
public List<View> findViews(InstrumentDescriptor descriptor, InstrumentationLibraryInfo meter) {
Copy link
Member

Choose a reason for hiding this comment

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

The only remaining usages of the singular version of this method above (public View findView(InstrumentDescriptor descriptor, InstrumentationLibraryInfo meter)) are in tests, so I believe it can be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great catch, will remove in next cleanup CL. Thought I had removed it in this branch, but apparently missed it.

}

/** Registers new asynchronous storage associated with a given {@code long} instrument. */
public final MetricStorage registerLongAsynchronousInstrument(
public final void registerLongAsynchronousInstrument(
Copy link
Member

Choose a reason for hiding this comment

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

These register methods are fairly repetitive. Could DRY it up with something like:

  public final WriteableMetricStorage registerSynchronousMetricStorage(
      InstrumentDescriptor instrument, MeterProviderSharedState meterProviderSharedState) {
    List<SynchronousMetricStorage<?>> storage =
        register(
            instrument,
            meterProviderSharedState,
            view ->
                SynchronousMetricStorage.create(
                    view,
                    instrument,
                    meterProviderSharedState.getResource(),
                    getInstrumentationLibraryInfo(),
                    meterProviderSharedState.getStartEpochNanos()));
    if (storage.size() == 1) {
      return storage.get(0);
    }
    // If the size is 0, we return an, effectively, no-op writer.
    return new MultiWritableMetricStorage(storage);
  }

  public final void registerLongAsynchronousInstrument(
      InstrumentDescriptor instrument,
      MeterProviderSharedState meterProviderSharedState,
      Consumer<ObservableLongMeasurement> metricUpdater) {
    register(
        instrument,
        meterProviderSharedState,
        view ->
            AsynchronousMetricStorage.longAsynchronousAccumulator(
                view,
                instrument,
                meterProviderSharedState.getResource(),
                getInstrumentationLibraryInfo(),
                meterProviderSharedState.getStartEpochNanos(),
                metricUpdater));
  }
  ..
  private <T extends MetricStorage> List<T> register(
      InstrumentDescriptor instrument,
      MeterProviderSharedState meterProviderSharedState,
      Function<View, T> storageFunction) {
    List<View> views =
        meterProviderSharedState
            .getViewRegistry()
            .findViews(instrument, getInstrumentationLibraryInfo());
    List<T> storage = new ArrayList<>(views.size());
    for (View view : views) {
      try {
        storage.add(getMetricStorageRegistry().register(storageFunction.apply(view)));
      } catch (DuplicateMetricStorageException e) {
        logger.log(Level.WARNING, e, () -> "Failed to register metric.");
      }
    }
    return storage;
  }

If you want to do this, you'd also have to change the constructor of MultiWritableMetricsStorage:

MultiWritableMetricStorage(List<? extends WriteableMetricStorage> metrics)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There's cleanup/fixes coming here in future PRs. TL;DR; we likely need a different registration mechanism for sync vs. async. Happy to discuss the details if you're interested, but expect these to diverge when we fix the issue that async instruments collect multiple times per collection period.

@jsuereth jsuereth deleted the wip-multi-views branch August 25, 2021 23:20
This was referenced Dec 19, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants