检测Application Insights是否(以及为什么)可以将遥测数据发送到Azure

时间:2015-12-23 08:20:47

标签: c# azure azure-application-insights

我正在开发Windows桌面应用程序并成功链接了Application Insights Core程序集。我使用TrackTraceTrackEvent等发送自定义遥测。

在某些工作站上,遥测成功发送到Azure门户,而在其他一些工作站上则没有,尽管对TrackTraceFlush等的调用成功(或者至少返回而没有抛出异常) 。TelemetryClient.IsEnabled()返回true。两个工作站都使用InMemoryChannel,端点https://dc.services.visualstudio.com/v2/track相同,发送间隔为30秒。

我可以在我的应用程序中调用API函数来获取TelemetryClient的连接状态吗?可以告诉我客户端已成功连接,或者在尝试时遇到错误 x ,但仍然有 y 遥测数据包等待发送。

我没有找到像重新安装NuGet包的清单(我做了......),确保您的防火墙允许流量到端口xxx (它确实...)或尝试安装kb ... 871 (我也这样做了......)。我喜欢的是一个状态报告,我可以在我的应用程序运行时在客户端工作站上的某个地方登录,至少在状态栏中确认(是的,我知道状态栏这些天很老式),这是一个问题

第一次更新 - 获取队列大小

第一次胜利,我能够获得队列大小。我想在不创建自己的频道实现的情况下做到这一点。然而,这对于检测中断几乎没有帮助,因为即使发送器无法发送遥测项目(它只会丢弃它们),队列也会耗尽 - 稍后会更多。至少你知道发射机线程正在运行......

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;
}

你还需要一个实用程序函数来使用反射来访问对象的私有字段(缓冲区和发送器是internal sealed ...)我尽可能地使它们具有抗错性,它们可以更简洁。

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);
}

2 个答案:

答案 0 :(得分:1)

好的,我设法让它工作......没有API可以做到这一点,所以我创建了一个新的自定义遥测频道,实际报告错误,我可以依赖。

编辑:从评论中可以看出ReliableTelemetryChannel不是此类的合适名称。它应该命名为ProbingTelemetryChannel。感谢。

using System;
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.Extensibility.Implementation;

namespace Streambolics.Telemetry
{
  public class ReliableTelemetryChannel : ITelemetryChannel
  {
    private Uri _EndpointAddress;
    private int _Attempts, _Successes, _Failures;
    private Exception _LastFailure;
    private DateTime _LastFailureTime;

    public ReliableTelemetryChannel ()
    {
      EndpointAddress = TelemetryConfiguration.Active?.TelemetryChannel?.EndpointAddress;
    }

    public bool? DeveloperMode {
        get { return true; }
        set { }
    }

    public string EndpointAddress {
        get { return _EndpointAddress?.ToString (); }
        set {
            if (String.IsNullOrEmpty (value))
                _EndpointAddress = null;
            else
                _EndpointAddress = new Uri (value);
        }
    }

    public void Flush () { }

    public void Send (ITelemetry item)
    {
      _Attempts++;

      try
      {
        item.Timestamp = DateTime.Now;
        byte[] data = JsonSerializer.Serialize (new ITelemetry[] { item });
        var transmission = new Transmission (_EndpointAddress, data, "application/x-json-stream", JsonSerializer.CompressionType);
        transmission.SendAsync ().GetAwaiter ().GetResult ();
        _Successes++;
      }
      catch (Exception ex)
      {
          _Failures++;
          _LastFailure = ex;
          _LastFailureTime = DateTime.Now;
      }
    }

    protected virtual void Dispose (bool disposing) { }
    public void Dispose ()
    { Dispose (true); }
  }
}

现在只需要在该频道上创建频道和客户端:

var _ReliableChannel = new ReliableTelemetryChannel ();
var _ReliableConfiguration = new TelemetryConfiguration ();
_ReliableConfiguration.TelemetryChannel = _ReliableChannel;
var _ReliableClient = new TelemetryClient (_ReliableConfiguration);
_ReliableClient.InstrumentationKey = "...";

现在我只是定期发送一个探测器,并在通道中查询错误统计信息:

_ReliableClient.TrackEvent ("TelemetryProbe");
GlobalLog.Log ("Probe attempts {0} Last Error {1}", _ReliableChannel.Attempts, _ReliableChannel.LastFailure);

它没有解决检测活动配置是否有效的全局问题(我用来发送常规遥测,缓冲等),但至少我可以放心地假设我的Reliable频道是工作,常规工作也在工作。

答案 1 :(得分:1)

注意:持久性通道在我写完后不久就停止了。

你得到它的工作,但你所做的只是创建一个已经存在的持久性通道。

您应该完成以下操作:

  using Microsoft.ApplicationInsights.Channel;
  using Microsoft.ApplicationInsights.Extensibility;
  ...

  // Set up 
  TelemetryConfiguration.Active.InstrumentationKey = "YOUR INSTRUMENTATION KEY";

  TelemetryConfiguration.Active.TelemetryChannel = new PersistenceChannel();

在应用程序退出时,请确保调用

telemetryClient.Flush()

将遥测数据刷新到频道。

这样做是将遥测数据写入磁盘并定期将数据刷新到Azure云。这非常适合间歇性互联网连接,也适用于应用程序在所有数据发送之前关闭的情况。

启动时,您可以添加一个微小的睡眠延迟,以确保将上一个会话的数据发送到云端。

代码示例取自Application Insights Documentation,可以找到更多详细信息。