5
5
using System . Collections . Generic ;
6
6
using System . Diagnostics ;
7
7
using System . IO ;
8
+ using System . Linq ;
8
9
using System . Management . Automation ;
9
10
using System . Runtime . InteropServices ;
11
+ using System . Security . AccessControl ;
10
12
using System . Threading ;
11
13
12
14
using Microsoft . ApplicationInsights ;
15
+ using Microsoft . ApplicationInsights . Metrics ;
13
16
using Microsoft . ApplicationInsights . Channel ;
14
17
using Microsoft . ApplicationInsights . Extensibility ;
15
18
using Microsoft . ApplicationInsights . Extensibility . Implementation ;
@@ -124,6 +127,9 @@ public static class ApplicationInsightsTelemetry
124
127
// Use '0.0' as the string for an anonymous module version
125
128
private const string AnonymousVersion = "0.0" ;
126
129
130
+ // Use 'n/a' as the string when there's no tag to report
131
+ private const string NoTag = "n/a" ;
132
+
127
133
// the telemetry failure string
128
134
private const string _telemetryFailure = "TELEMETRY_FAILURE" ;
129
135
@@ -140,9 +146,11 @@ public static class ApplicationInsightsTelemetry
140
146
private static int s_startupEventSent = 0 ;
141
147
142
148
/// Use a hashset for quick lookups.
143
- /// We send telemetry only a known set of modules.
144
- /// If it's not in the list (initialized in the static constructor), then we report anonymous.
149
+ /// We send telemetry only a known set of modules and tags.
150
+ /// If it's not in the list (initialized in the static constructor), then we report anonymous
151
+ /// or don't report anything (in the case of tags).
145
152
private static readonly HashSet < string > s_knownModules ;
153
+ private static readonly HashSet < string > s_knownModuleTags ;
146
154
147
155
/// <summary>Gets a value indicating whether telemetry can be sent.</summary>
148
156
public static bool CanSendTelemetry { get ; private set ; } = false ;
@@ -601,6 +609,12 @@ static ApplicationInsightsTelemetry()
601
609
"xWindowsUpdate" ,
602
610
} ;
603
611
612
+ // use a hashset when looking for module names, it should be quicker than a string comparison
613
+ s_knownModuleTags = new HashSet < string > ( StringComparer . OrdinalIgnoreCase )
614
+ {
615
+ "CrescendoBuilt" ,
616
+ } ;
617
+
604
618
s_uniqueUserIdentifier = GetUniqueIdentifier ( ) . ToString ( ) ;
605
619
}
606
620
}
@@ -671,15 +685,49 @@ private static bool GetEnvironmentVariableAsBool(string name, bool defaultValue)
671
685
return defaultValue ;
672
686
}
673
687
688
+ /// <summary>
689
+ /// Send module load telemetry as a metric.
690
+ /// For modules we send the module name (if allowed), and the version.
691
+ /// Some modules (CIM) will continue use the string alternative method.
692
+ /// </summary>
693
+ /// <param name="telemetryType">The type of telemetry that we'll be sending.</param>
694
+ /// <param name="moduleInfo">The module to report. If it is not allowed, then it is set to 'anonymous'.</param>
695
+ internal static void SendModuleTelemetryMetric ( TelemetryType telemetryType , PSModuleInfo moduleInfo )
696
+ {
697
+ if ( ! CanSendTelemetry )
698
+ {
699
+ return ;
700
+ }
701
+
702
+ // Package up the module name, version, and known tags as a metric.
703
+ // Note that the allowed tags will be a comma separated list which will need to
704
+ // be handled in the telemetry query.
705
+ try
706
+ {
707
+ string allowedModuleName = GetModuleName ( moduleInfo . Name ) ;
708
+ string allowedModuleVersion = allowedModuleName == Anonymous ? AnonymousVersion : moduleInfo . Version ? . ToString ( ) ;
709
+ var allowedModuleTags = moduleInfo . Tags . Where ( t => s_knownModuleTags . Contains ( t ) ) . Distinct ( ) ;
710
+ string allowedModuleTagString = allowedModuleTags . Any ( ) ? string . Join ( ',' , allowedModuleTags ) : NoTag ;
711
+
712
+ s_telemetryClient .
713
+ GetMetric ( new MetricIdentifier ( string . Empty , telemetryType . ToString ( ) , "uuid" , "SessionId" , "ModuleName" , "Version" , "Tag" ) ) .
714
+ TrackValue ( metricValue : 1.0 , s_uniqueUserIdentifier , s_sessionId , allowedModuleName , allowedModuleVersion , allowedModuleTagString ) ;
715
+ }
716
+ catch
717
+ {
718
+ // Ignore errors.
719
+ }
720
+
721
+ }
722
+
674
723
/// <summary>
675
724
/// Send module load telemetry as a metric.
676
725
/// For modules we send the module name (if allowed), and the version.
677
726
/// Some modules (CIM) will continue use the string alternative method.
678
727
/// </summary>
679
728
/// <param name="telemetryType">The type of telemetry that we'll be sending.</param>
680
729
/// <param name="moduleName">The module name to report. If it is not allowed, then it is set to 'anonymous'.</param>
681
- /// <param name="moduleVersion">The module version to report. The default value is the anonymous version '0.0.0.0'.</param>
682
- internal static void SendModuleTelemetryMetric ( TelemetryType telemetryType , string moduleName , string moduleVersion = AnonymousVersion )
730
+ internal static void SendModuleTelemetryMetric ( TelemetryType telemetryType , string moduleName )
683
731
{
684
732
if ( ! CanSendTelemetry )
685
733
{
@@ -689,8 +737,7 @@ internal static void SendModuleTelemetryMetric(TelemetryType telemetryType, stri
689
737
try
690
738
{
691
739
string allowedModuleName = GetModuleName ( moduleName ) ;
692
- string allowedModuleVersion = allowedModuleName == Anonymous ? AnonymousVersion : moduleVersion ;
693
- s_telemetryClient . GetMetric ( telemetryType . ToString ( ) , "uuid" , "SessionId" , "ModuleName" , "Version" ) . TrackValue ( metricValue : 1.0 , s_uniqueUserIdentifier , s_sessionId , allowedModuleName , allowedModuleVersion ) ;
740
+ s_telemetryClient . GetMetric ( telemetryType . ToString ( ) , "uuid" , "SessionId" , "ModuleName" , "Version" ) . TrackValue ( metricValue : 1.0 , s_uniqueUserIdentifier , s_sessionId , allowedModuleName , AnonymousVersion ) ;
694
741
}
695
742
catch
696
743
{
0 commit comments