Skip to content

Commit

Permalink
Handle the MeasurmentsCompleted event.
Browse files Browse the repository at this point in the history
  • Loading branch information
nrcventura committed Nov 8, 2024
1 parent 6b2147e commit 8c6b04f
Showing 1 changed file with 67 additions and 21 deletions.
88 changes: 67 additions & 21 deletions src/Agent/NewRelic/Agent/Core/Samplers/MeterListenerBridge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,38 +81,42 @@ private void TryCreateMeterListener()
{
_meterListener = Activator.CreateInstance(meterListenerType);

var instrumentPublishProperty = meterListenerType.GetProperty("InstrumentPublished");
SubscribeToInstrumentPublishedEvent(meterListenerType, instrumentType);

var instrumentParameter = Expression.Parameter(instrumentType, "instrument");
var listenerParameter = Expression.Parameter(meterListenerType, "listener");
SubscribeToMeasurementUpdates<byte>(meterListenerType, instrumentType);
SubscribeToMeasurementUpdates<short>(meterListenerType, instrumentType);
SubscribeToMeasurementUpdates<int>(meterListenerType, instrumentType);
SubscribeToMeasurementUpdates<long>(meterListenerType, instrumentType);
SubscribeToMeasurementUpdates<float>(meterListenerType, instrumentType);
SubscribeToMeasurementUpdates<double>(meterListenerType, instrumentType);
SubscribeToMeasurementUpdates<decimal>(meterListenerType, instrumentType);

var meterNameProperty = Expression.Property(Expression.Property(instrumentParameter, "Meter"), "Name");
SubscribeToMeasurementCompletedEvent(meterListenerType, instrumentType);
}
}

var shouldEnableMethod = typeof(MeterListenerBridge).GetMethod(nameof(ShouldEnableInstrumentsInMeter), BindingFlags.NonPublic | BindingFlags.Static);
var shouldEnableCall = Expression.Call(null, shouldEnableMethod, meterNameProperty);
private void SubscribeToInstrumentPublishedEvent(Type meterListenerType, Type instrumentType)
{
var instrumentPublishProperty = meterListenerType.GetProperty("InstrumentPublished");

var getInstrumentStateMethod = typeof(MeterListenerBridge).GetMethod(nameof(GetStateForInstrument), BindingFlags.NonPublic | BindingFlags.Static);
var getInstrumentStateCall = Expression.Call(null, getInstrumentStateMethod, instrumentParameter);
var instrumentParameter = Expression.Parameter(instrumentType, "instrument");
var listenerParameter = Expression.Parameter(meterListenerType, "listener");

var enableMeasurementEventsMethod = Expression.Call(listenerParameter, "EnableMeasurementEvents", null, instrumentParameter, getInstrumentStateCall);
var meterNameProperty = Expression.Property(Expression.Property(instrumentParameter, "Meter"), "Name");

var lambdaBody = Expression.IfThen(shouldEnableCall, enableMeasurementEventsMethod);
var shouldEnableMethod = typeof(MeterListenerBridge).GetMethod(nameof(ShouldEnableInstrumentsInMeter), BindingFlags.NonPublic | BindingFlags.Static);
var shouldEnableCall = Expression.Call(null, shouldEnableMethod, meterNameProperty);

var lambda = Expression.Lambda(instrumentPublishProperty.PropertyType, lambdaBody, instrumentParameter, listenerParameter);
var getInstrumentStateMethod = typeof(MeterListenerBridge).GetMethod(nameof(GetStateForInstrument), BindingFlags.NonPublic | BindingFlags.Static);
var getInstrumentStateCall = Expression.Call(null, getInstrumentStateMethod, instrumentParameter);

instrumentPublishProperty.SetValue(_meterListener, lambda.Compile());
var enableMeasurementEventsMethod = Expression.Call(listenerParameter, "EnableMeasurementEvents", null, instrumentParameter, getInstrumentStateCall);

var lambdaBody = Expression.IfThen(shouldEnableCall, enableMeasurementEventsMethod);

SubscribeToMeasurementUpdates<byte>(meterListenerType, instrumentType);
SubscribeToMeasurementUpdates<short>(meterListenerType, instrumentType);
SubscribeToMeasurementUpdates<int>(meterListenerType, instrumentType);
SubscribeToMeasurementUpdates<long>(meterListenerType, instrumentType);
SubscribeToMeasurementUpdates<float>(meterListenerType, instrumentType);
SubscribeToMeasurementUpdates<double>(meterListenerType, instrumentType);
SubscribeToMeasurementUpdates<decimal>(meterListenerType, instrumentType);
var lambda = Expression.Lambda(instrumentPublishProperty.PropertyType, lambdaBody, instrumentParameter, listenerParameter);

// TODO: Subscribe to MeasurementCompleted event to remove the corresponding bridged instrument
}
instrumentPublishProperty.SetValue(_meterListener, lambda.Compile());
}

private void SubscribeToMeasurementUpdates<T>(Type meterListenerType, Type instrumentType)
Expand All @@ -138,6 +142,48 @@ private void SubscribeToMeasurementUpdates<T>(Type meterListenerType, Type instr
setMeasurementEventCallbackMethodInfo.Invoke(_meterListener, new object[] { measurementRecordedLambda.Compile() });
}

private void SubscribeToMeasurementCompletedEvent(Type meterListenerType, Type instrumentType)
{
var measurementsCompletedProperty = meterListenerType.GetProperty("MeasurementsCompleted");

var instrumentParameter = Expression.Parameter(instrumentType, "instrument");
var stateParameter = Expression.Parameter(typeof(object), "state");

var disableBridgedInstrumentMethod = typeof(MeterListenerBridge).GetMethod(nameof(DisableBridgedInstrument), BindingFlags.NonPublic | BindingFlags.Static);
var disableBridgedInstrumentCall = Expression.Call(null, disableBridgedInstrumentMethod, stateParameter);

var measurmentsCompletedLambda = Expression.Lambda(measurementsCompletedProperty.PropertyType, disableBridgedInstrumentCall, instrumentParameter, stateParameter);

measurementsCompletedProperty.SetValue(_meterListener, measurmentsCompletedLambda.Compile());
}

private static void DisableBridgedInstrument(object state)
{
if (state == null)
{
return;
}

var bridgedInstrument = state as Instrument;
if (bridgedInstrument == null)
{
return;
}

// The MeasurementsCompleted event is triggered when an instrument is no longer being subscribed to by a MeterListener
// or the Meter holding the instrumented is Disposed. In our use case, we subscribe to all instruments in a meter and
// do not disable individual individual instruments, so the only way this event will be triggered is if the corresponding
// meter is no longer being used by the application or if our MeterListener is being Disposed. In either case we can
// just Dispose of the bridged Meter.

if (_bridgedMeters.TryRemove(bridgedInstrument.Meter.Name, out var bridgedMeter))
{
var meterName = bridgedMeter.Name;
bridgedMeter.Dispose();
Console.WriteLine("Disposed bridged meter: " + meterName);
}
}


private static bool ShouldEnableInstrumentsInMeter(string meterName)
{
Expand Down

0 comments on commit 8c6b04f

Please sign in to comment.