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

Hotfix(metrics): CNX-9196 add object type event tracking for mixpanel in autocad, rhino, and revit #3257

Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ string id
var conversionProgressDict = new ConcurrentDictionary<string, int>();
conversionProgressDict["Conversion"] = 0;

// track object types for mixpanel logging
Dictionary<string, int> typeCountDict = new();

// create a commit prefix: used for layers and block definition names
var commitPrefix = Formatting.CommitInfo(stream.name, state.BranchName, id);

Expand Down Expand Up @@ -217,20 +220,30 @@ string id
return;
}

// convert base (or base fallback values) and store in appobj converted prop
if (commitObj.Convertible)
if (StoredObjects.TryGetValue(commitObj.OriginalId, out Base commitBaseObj))
{
if (StoredObjects.TryGetValue(commitObj.OriginalId, out Base obj))
// log received object type
if (typeCountDict.TryGetValue(commitBaseObj.speckle_type, out int value))
{
converter.Report.Log(commitObj); // Log object so converter can access
commitObj.Converted = ConvertObject(obj, converter);
typeCountDict[commitBaseObj.speckle_type] = ++value;
}
else
{
commitObj.Update(status: ApplicationObject.State.Failed, logItem: "Object not found in StoredObjects");
typeCountDict.Add(commitBaseObj.speckle_type, 1);
}
}
else
{
commitObj.Update(status: ApplicationObject.State.Failed, logItem: "Object not found in StoredObjects");
}

// convert base (or base fallback values) and store in appobj converted prop
if (commitObj.Convertible)
{
converter.Report.Log(commitObj); // Log object so converter can access
commitObj.Converted = ConvertObject(commitBaseObj, converter);
}
else
{
foreach (ApplicationObject fallback in commitObj.Fallback)
{
Expand Down Expand Up @@ -271,6 +284,21 @@ string id
}
progress.Report.Merge(converter.Report);

// track the object type counts as an event before we try to receive
// this will tell us the composition of a commit the user is trying to receive, even if it's not successfully received
// we are capped at 255 properties for mixpanel events, so we need to check dict entries
var typeCountArray = typeCountDict
.ToArray()
.Select(o => new { TypeName = o.Key, Count = o.Value })
.OrderBy(pair => pair.Count)
.Reverse()
.Take(250);
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps we can encode this value as a constant inside the Analytics class, just so we avoid having magic numbers

Copy link
Member

Choose a reason for hiding this comment

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

SInce the limit in mixpanel is 255, and we might be adding some other default props, I would lower it to 230 or so to be safe, maybe even 200.


Analytics.TrackEvent(
Analytics.Events.ConvertToNative,
new Dictionary<string, object>() { { "typeCount", typeCountArray } }
);

// add applicationID xdata before bake
if (!ApplicationIdManager.AddApplicationIdXDataToDoc(Doc, tr))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ ref int convertedCount
var commitLayerObjects = new Dictionary<string, List<Base>>();
var commitCollections = new Dictionary<string, Collection>();

// track object types for mixpanel logging
Dictionary<string, int> typeCountDict = new();

foreach (var autocadObjectHandle in state.SelectedObjectIds)
{
// handle user cancellation
Expand All @@ -201,6 +204,17 @@ ref int convertedCount
continue;
}

// log selection object type
var objectType = obj.GetType().ToString();
if (typeCountDict.TryGetValue(objectType, out int value))
{
typeCountDict[objectType] = ++value;
}
else
{
typeCountDict.Add(objectType, 1);
}

// create applicationobject for reporting
Base converted = null;
var descriptor = ObjectDescriptor(obj);
Expand Down Expand Up @@ -342,6 +356,21 @@ bool isOldApplicationId(string appId)

#endregion

// track the object type counts as an event before we try to send
// this will tell us the composition of a commit the user is trying to convert and send, even if it's not successfully converted or sent
// we are capped at 255 properties for mixpanel events, so we need to check dict entries
var typeCountArray = typeCountDict
.ToArray()
.Select(o => new { TypeName = o.Key, Count = o.Value })
.OrderBy(pair => pair.Count)
.Reverse()
.Take(250);

Analytics.TrackEvent(
Analytics.Events.ConvertToSpeckle,
new Dictionary<string, object>() { { "typeCount", typeCountArray } }
);

tr.Commit();
}
}
Expand Down
29 changes: 29 additions & 0 deletions ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Receive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ public override async Task<StreamState> ReceiveStream(StreamState state, Progres

converter.SetConverterSettings(settings);

// track object types for mixpanel logging
Dictionary<string, int> typeCountDict = new();

Commit myCommit = await ConnectorHelpers.GetCommitFromState(state, progress.CancellationToken);
state.LastCommit = myCommit;
Base commitObject = await ConnectorHelpers.ReceiveCommit(myCommit, state, progress);
Expand All @@ -70,8 +73,34 @@ await ConnectorHelpers.TryCommitReceived(
foreach (var previewObj in Preview)
{
progress.Report.Log(previewObj);
if (StoredObjects.TryGetValue(previewObj.OriginalId, out Base previewBaseObj))
{
if (typeCountDict.TryGetValue(previewBaseObj.speckle_type, out int value))
{
typeCountDict[previewBaseObj.speckle_type] = ++value;
}
else
{
typeCountDict.Add(previewBaseObj.speckle_type, 1);
}
}
}

// track the object type counts as an event before we try to receive
// this will tell us the composition of a commit the user is trying to convert and receive, even if it's not successfully converted or received
// we are capped at 255 properties for mixpanel events, so we need to check dict entries
var typeCountArray = typeCountDict
.ToArray()
.Select(o => new { TypeName = o.Key, Count = o.Value })
.OrderBy(pair => pair.Count)
.Reverse()
.Take(250);

Analytics.TrackEvent(
Analytics.Events.ConvertToNative,
new Dictionary<string, object>() { { "typeCount", typeCountArray } }
);

converter.ReceiveMode = state.ReceiveMode;
// needs to be set for editing to work
var previousObjects = new StreamStateCache(state);
Expand Down
31 changes: 31 additions & 0 deletions ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Send.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ public override async Task<string> SendStream(StreamState state, ProgressViewMod
var conversionProgressDict = new ConcurrentDictionary<string, int> { ["Conversion"] = 0 };
var convertedCount = 0;

// track object types for mixpanel logging
Dictionary<string, int> typeCountDict = new();

await APIContext
.Run(() =>
{
Expand All @@ -114,6 +117,17 @@ await APIContext
break;
}

// log selected object type
string revitObjectType = revitElement.GetType().ToString();
if (typeCountDict.TryGetValue(revitObjectType, out int value))
{
typeCountDict[revitObjectType] = ++value;
}
else
{
typeCountDict.Add(revitObjectType, 1);
}

bool isAlreadyConverted = GetOrCreateApplicationObject(
revitElement,
converter.Report,
Expand All @@ -136,10 +150,12 @@ out ApplicationObject reportObj

Base result = ConvertToSpeckle(revitElement, converter);

// log converted object
reportObj.Update(
status: ApplicationObject.State.Created,
logItem: $"Sent as {ConnectorRevitUtils.SimplifySpeckleType(result.speckle_type)}"
);

if (result.applicationId != reportObj.applicationId)
{
SpeckleLog.Logger.Information(
Expand Down Expand Up @@ -180,6 +196,21 @@ out ApplicationObject reportObj
throw new SpeckleException("Zero objects converted successfully. Send stopped.");
}

// track the object type counts as an event before we try to send
// this will tell us the composition of a commit the user is trying to convert and send, even if it's not successfully converted or sent
// we are capped at 255 properties for mixpanel events, so we need to check dict entries
var typeCountArray = typeCountDict
.ToArray()
.Select(o => new { TypeName = o.Key, Count = o.Value })
.OrderBy(pair => pair.Count)
.Reverse()
.Take(250);

Analytics.TrackEvent(
Analytics.Events.ConvertToSpeckle,
new Dictionary<string, object>() { { "typeCount", typeCountArray } }
);
Copy link
Member

Choose a reason for hiding this comment

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

Wondering if this could go in a helper function, but up to you guys...


commitObjectBuilder.BuildCommitObject(commitObject);

var transports = new List<ITransport>() { new ServerTransport(client.Account, streamId) };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ public override async Task<StreamState> ReceiveStream(StreamState state, Progres
var conversionProgressDict = new ConcurrentDictionary<string, int>();
conversionProgressDict["Conversion"] = 0;

// track object types for mixpanel logging
Dictionary<string, int> typeCountDict = new();

Base commitObject = null;
if (Preview.Count == 0)
{
Expand Down Expand Up @@ -161,6 +164,7 @@ await ConnectorHelpers.TryCommitReceived(
.Where(o => !string.IsNullOrEmpty(o))
.OrderBy(path => path.Count(c => c == ':'))
.ToList();

// if on create mode, make sure the parent commit layer is created first
if (state.ReceiveMode == ReceiveMode.Create)
{
Expand All @@ -185,6 +189,7 @@ await ConnectorHelpers.TryCommitReceived(
var collection = Preview
.Where(o => o.Container == container && o.Descriptor.Contains("Collection"))
.FirstOrDefault();

if (collection != null)
{
var storedCollection = StoredObjects[collection.OriginalId];
Expand Down Expand Up @@ -217,6 +222,19 @@ await ConnectorHelpers.TryCommitReceived(

foreach (var previewObj in Preview)
{
// log received object type
if (StoredObjects.TryGetValue(previewObj.OriginalId, out Base previewBaseObj))
{
if (typeCountDict.TryGetValue(previewBaseObj.speckle_type, out int value))
{
typeCountDict[previewBaseObj.speckle_type] = ++value;
}
else
{
typeCountDict.Add(previewBaseObj.speckle_type, 1);
}
}

if (previewObj.Status != ApplicationObject.State.Unknown)
{
continue; // this has already been converted and baked
Expand Down Expand Up @@ -303,6 +321,21 @@ await ConnectorHelpers.TryCommitReceived(

RhinoDoc.LayerTableEvent += RhinoDoc_LayerChange; // reactivate the layer handler

// track the object type counts as an event before we try to receive
// this will tell us the composition of a commit the user is trying to convert and receive, even if it's not successfully converted or received
// we are capped at 255 properties for mixpanel events, so we need to check dict entries
var typeCountArray = typeCountDict
.ToArray()
.Select(o => new { TypeName = o.Key, Count = o.Value })
.OrderBy(pair => pair.Count)
.Reverse()
.Take(250);

Speckle.Core.Logging.Analytics.TrackEvent(
Speckle.Core.Logging.Analytics.Events.ConvertToNative,
new Dictionary<string, object>() { { "typeCount", typeCountArray } }
);

// undo notes edit
var segments = Doc.Notes.Split(new[] { "%%%" }, StringSplitOptions.None).ToList();
Doc.Notes = segments[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ public override async Task<string> SendStream(StreamState state, ProgressViewMod
var commitLayers = new Dictionary<string, Layer>();
var commitCollections = new Dictionary<string, Collection>();

// track object types for mixpanel logging
Dictionary<string, int> typeCountDict = new();

// convert all commit objs
foreach (var selectedId in state.SelectedObjectIds)
{
Expand All @@ -63,6 +66,17 @@ public override async Task<string> SendStream(StreamState state, ProgressViewMod
var reportObj = new ApplicationObject(selectedId, "Unknown");
if (Utils.FindObjectBySelectedId(Doc, selectedId, out object obj, out string descriptor))
{
// log selection object type
var objectType = obj.GetType().ToString();
if (typeCountDict.TryGetValue(objectType, out int value))
{
typeCountDict[objectType] = ++value;
}
else
{
typeCountDict.Add(objectType, 1);
}

// create applicationObject
reportObj = new ApplicationObject(selectedId, descriptor);
converter.Report.Log(reportObj); // Log object so converter can access
Expand Down Expand Up @@ -228,10 +242,26 @@ void AddParent(Layer childLayer)
throw new SpeckleException("Zero objects converted successfully. Send stopped.");
}

// track the object type counts as an event before we try to send
// this will tell us the composition of a commit the user is trying to convert and send, even if it's not successfully converted or sent
// we are capped at 255 properties for mixpanel events, so we need to check dict entries
var typeCountArray = typeCountDict
.ToArray()
.Select(o => new { TypeName = o.Key, Count = o.Value })
.OrderBy(pair => pair.Count)
.Reverse()
.Take(250);

Speckle.Core.Logging.Analytics.TrackEvent(
Speckle.Core.Logging.Analytics.Events.ConvertToSpeckle,
new Dictionary<string, object>() { { "typeCount", typeCountArray } }
);

progress.CancellationToken.ThrowIfCancellationRequested();

progress.Max = objCount;

// send the commit
var transports = new List<ITransport> { new ServerTransport(client.Account, streamId) };

var objectId = await Operations.Send(
Expand Down Expand Up @@ -260,6 +290,7 @@ void AddParent(Layer childLayer)
}

var commitId = await ConnectorHelpers.CreateCommit(client, actualCommit, progress.CancellationToken);

return commitId;
}
}
12 changes: 11 additions & 1 deletion Core/Core/Logging/Analytics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,17 @@ public enum Events
/// <summary>
/// Event triggered by the Mapping Tool
/// </summary>
MappingsAction
MappingsAction,

/// <summary>
/// Event triggered when user selects object to convert to Speckle on Send
/// </summary>
ConvertToSpeckle,

/// <summary>
/// Event triggered when user selects object to convert to Native on Receive
/// </summary>
ConvertToNative
}

private const string MIXPANEL_TOKEN = "acd87c5a50b56df91a795e999812a3a4";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ public Base ConvertToSpeckle(object @object)
break;
case AcadDB.Polyline o:
@base = o.IsOnlyLines ? PolylineToSpeckle(o) : (Base)PolycurveToSpeckle(o);

break;
case AcadDB.Polyline3d o:
@base = PolylineToSpeckle(o);
Expand Down