Skip to content

Commit

Permalink
DYN-6030 Log Heartbeat events to log active/idle states (#14684)
Browse files Browse the repository at this point in the history
* Fix PostDiff job

* log heartbeat

* Optimize logging and add mouse and key press events log

* Update DynamoAnalyticsClient.cs

* add machine tracking status

* comments

* Update Analytics nuget

* add to test
  • Loading branch information
zeusongit authored Dec 13, 2023
1 parent 061a79b commit cfad5a1
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/DynamoCore/DynamoCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<PackageReference Include="Lucene.Net" Version="4.8.0-beta00016" />
<PackageReference Include="Lucene.Net.Analysis.Common" Version="4.8.0-beta00016" />
<PackageReference Include="Lucene.Net.QueryParser" Version="4.8.0-beta00016" />
<PackageReference Include="DynamoVisualProgramming.Analytics" Version="4.2.0.3351" />
<PackageReference Include="DynamoVisualProgramming.Analytics" Version="4.2.0.3421" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Engine\GraphLayout\GraphLayout.csproj">
Expand Down
54 changes: 54 additions & 0 deletions src/DynamoCore/Logging/DynamoAnalyticsClient.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Autodesk.Analytics.ADP;
Expand Down Expand Up @@ -96,6 +97,10 @@ public void Dispose() { }

public virtual IAnalyticsSession Session { get; private set; }

private DateTime LastMachineHBLogTime;
private DateTime LastUserHBLogTime;
private readonly int HeartBeatInterval = 4;

/// <summary>
/// Return if Analytics Client is allowed to send any analytics information
/// </summary>
Expand Down Expand Up @@ -255,6 +260,55 @@ public void TrackScreenView(string viewName)
}
});
}
/// <summary>
/// This API is used to track user/machine's activity status.
/// Note: This will not trigger the API at each call, instead it will
/// send out one call for every 4(HeartBeatInterval) minutes for each user and machine type activity.
/// For example, if the method gets called 100 times in 8 minutes, then it will only
/// trigger the HeartBeat API twice. This is to avoid sending out too many calls
/// as the API expects a call every 5 minutes, to mark the user/machine active.
/// </summary>
/// <param name="activityType">Value must be either Machine or User. If no value is provided the API will default to user activity type.</param>
public void TrackActivityStatus(string activityType)
{
if (Analytics.DisableAnalytics) return;

Task.Run(() =>
{
serviceInitialized.Wait();
lock (trackEventLockObj)
{
if (!ReportingAnalytics) return;
var hbType = (new[] { HeartBeatType.Machine.ToString(), HeartBeatType.User.ToString() }).Contains(activityType) ? activityType : HeartBeatType.User.ToString();
LogHeartBeat(hbType);
}
});
}

private void LogHeartBeat(string activityType)
{
if (activityType == HeartBeatType.Machine.ToString())
{
//Only send log if atleast 4 minutes have been passed since the last log.
if (LastMachineHBLogTime != null && DateTime.UtcNow > LastMachineHBLogTime.AddMinutes(HeartBeatInterval))
{
LastMachineHBLogTime = DateTime.UtcNow;
var e = new HeartBeatEvent(activityType);
e.Track();
}
}
else
{
if (LastUserHBLogTime != null && DateTime.UtcNow > LastUserHBLogTime.AddMinutes(HeartBeatInterval))
{
LastUserHBLogTime = DateTime.UtcNow;
var e = new HeartBeatEvent(activityType);
e.Track();
}
}
}

public void TrackException(Exception ex, bool isFatal)
{
Expand Down
5 changes: 5 additions & 0 deletions src/DynamoCore/Scheduler/UpdateGraphAsyncTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using ProtoScript.Runners;
using Dynamo.Graph.Nodes;
using Dynamo.Graph.Workspaces;
using Dynamo.Logging;

namespace Dynamo.Scheduler
{
Expand Down Expand Up @@ -103,7 +104,10 @@ protected override void HandleTaskExecutionCore()
// EngineController might be disposed and become invalid.
// After MAGN-5167 is done, we could remove this checking.
if (!engineController.IsDisposed)
{
Analytics.TrackActivityStatus(HeartBeatType.Machine.ToString());
engineController.UpdateGraphImmediate(graphSyncData);
}
}

protected override void HandleTaskCompletionCore()
Expand All @@ -116,6 +120,7 @@ protected override void HandleTaskCompletionCore()
}
else
{
Analytics.TrackActivityStatus(HeartBeatType.Machine.ToString());
// Retrieve warnings in the context of ISchedulerThread.
BuildWarnings = engineController.GetBuildWarnings();
RuntimeWarnings = engineController.GetRuntimeWarnings();
Expand Down
2 changes: 0 additions & 2 deletions src/DynamoCoreWpf/ViewModels/Core/StateMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@
using System.Linq;
using System.Windows;
using System.Windows.Input;
using Dynamo.Controls;
using Dynamo.Graph;
using Dynamo.Graph.Annotations;
using Dynamo.Graph.Nodes;
using Dynamo.Graph.Notes;
using Dynamo.Graph.Workspaces;
using Dynamo.Models;
using Dynamo.Nodes;
using Dynamo.Selection;
using Dynamo.Utilities;
using Dynamo.Wpf.Utilities;
Expand Down
2 changes: 2 additions & 0 deletions src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2038,6 +2038,7 @@ private void WindowClosed(object sender, EventArgs e)
// passes it to thecurrent workspace
private void DynamoView_KeyDown(object sender, KeyEventArgs e)
{
Analytics.TrackActivityStatus(HeartBeatType.User.ToString());
if (e.Key != Key.Escape || !IsMouseOver) return;

var vm = dynamoViewModel.BackgroundPreviewViewModel;
Expand Down Expand Up @@ -2784,6 +2785,7 @@ private void _resizeTimer_Tick(object sender, EventArgs e)

private void Window_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
Analytics.TrackActivityStatus(HeartBeatType.User.ToString());
dynamoViewModel.IsMouseDown = true;
}

Expand Down
9 changes: 9 additions & 0 deletions src/NodeServices/Analytics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ public static void TrackScreenView(string viewName)
if (client != null) client.TrackScreenView(viewName);
}

/// <summary>
/// Tracks user/machine idle and active states while using the application.
/// </summary>
/// <param name="activityType">Defines the activity type i.e: machine or user</param>
public static void TrackActivityStatus(string activityType)
{
if (client != null) client.TrackActivityStatus(activityType);
}

/// <summary>
/// Tracks an exception. If the exception is fatal, its recorded as crash.
/// </summary>
Expand Down
13 changes: 13 additions & 0 deletions src/NodeServices/IAnalyticsClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,12 @@ public enum Actions
Export
}

public enum HeartBeatType
{
User,
Machine
}

/// <summary>
/// Implements analytics and logging functions. This interface is defined
/// for internal use only to implement analytics functions and mock the tests.
Expand Down Expand Up @@ -506,6 +512,13 @@ public interface IAnalyticsClient
/// <param name="isFatal">If it's fatal</param>
void TrackException(Exception ex, bool isFatal);

/// <summary>
/// This API is used to track user/machine's activity status.
/// </summary>
/// <param name="activityType">Value must be: machine or user. If no value is provided the API will default to user activity type.</param>
/// <returns>0 if successful, otherwise returns an error code.</returns>
void TrackActivityStatus(string activityType);

/// <summary>
/// Creates a new timed event with start state and tracks its start.
/// Disposing the returnd event will record the event completion.
Expand Down
3 changes: 3 additions & 0 deletions test/DynamoCoreTests/AnalyticsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ protected virtual void VerifyEventTracking(Times times)
Analytics.TrackScreenView("TestScreen");
clientMoq.Verify(c => c.TrackScreenView("TestScreen"), times);

Analytics.TrackActivityStatus("User");
clientMoq.Verify(c => c.TrackActivityStatus("User"), times);

TestAnalytics.TrackException<InvalidOperationException>(false);
clientMoq.Verify(c => c.TrackException(It.IsAny<InvalidOperationException>(), false), times);

Expand Down
2 changes: 1 addition & 1 deletion test/DynamoCoreTests/DynamoCoreTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<PackageReference Include="coverlet.collector" Version="3.1.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" ExcludeAssets="none" />
<PackageReference Include="JunitXml.TestLogger" Version="3.0.124" />
<PackageReference Include="DynamoVisualProgramming.Analytics" Version="4.2.0.3351">
<PackageReference Include="DynamoVisualProgramming.Analytics" Version="4.2.0.3421">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>compile; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down

0 comments on commit cfad5a1

Please sign in to comment.