I'm developing a Windows Desktop application and have successfully linked the Application Insights Core assemblies. I'm using TrackTrace
, TrackEvent
, etc. to send custom telemetry.
On some workstations telemetry is successfully sent to the Azure portal, and on some others it is not, although calls to TrackTrace
, Flush
, etc. succeed (or at least return without throwing an exception. TelemetryClient.IsEnabled()
returns true. Both workstations use an InMemoryChannel
, with the same endpoint https://dc.services.visualstudio.com/v2/track
and the sending interval is 30 seconds.
Is there an API function I can call in my application to get the connection status of the TelemetryClient? Something that would tell me that the client is successfully connected, or that it encountered error x while trying, and still has y telemetry packets waiting to be sent.
I'm not looking for a checklist like reinstall the NuGet package (I did...), Make sure your firewall allows traffic to port xxx (it does...) or try to install kb...871 (I did that too...). What I'd like is a status report that I can log somewhere on the client workstation while my application runs, at least acknowledging in the status bar (Yes I know status bars are so old fashioned these days) that there is a problem.
First update - Getting the queue size
First victory, I was able to get the queue size. I wanted to do that without creating my own channel implementation (yet). This however is of little help to detect outages, because the queue will drain even if the transmitter is unable to transmit the telemetry items (it will just discard them) - more on this later. At least you know the transmitter thread is running...
private ITelemetryChannel _TelemetryChannel;
private InMemoryChannel _InMemoryChannel;
private object _TelemetryBuffer;
private object _BufferLock;
private object _InMemoryTransmitter;
_TelemetryChannel = TelemetryConfiguration.Active?.TelemetryChannel;
if (_TelemetryChannel != null && _TelemetryChannel is InMemoryChannel)
{
_InMemoryChannel = (InMemoryChannel)_TelemetryChannel;
_TelemetryBuffer = GetInstanceField (_InMemoryChannel, "buffer");
_BufferLock = GetInstanceField (_TelemetryBuffer, "lockObj");
_InMemoryTransmitter = GetInstanceField (_InMemoryChannel, "transmitter");
}
public int GetTelemetryQueueSize ()
{
if (_BufferLock != null)
{
lock (_BufferLock)
{
object l = GetInstanceField (_TelemetryBuffer, "items");
if (l is List<ITelemetry>)
{
return ((List<ITelemetry>)l).Count;
}
}
}
return -1;
}
You also need an utility function to use reflection to access the private fields of the objects (the buffer and transmitter are internal sealed
...) I made these as error resistant as possible, they could be more concise.
private static object GetInstanceField (Type type, object instance, string fieldName)
{
if (instance == null)
{
return null;
}
try
{
BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
FieldInfo field = type.GetField (fieldName, bindFlags);
return field.GetValue (instance);
}
catch
{
return null;
}
}
private static object GetInstanceField (object instance, string fieldName)
{
if (instance == null)
{
return null;
}
return GetInstanceField (instance.GetType (), instance, fieldName);
}