3
3
4
4
using Microsoft . Build . Execution ;
5
5
using Microsoft . Build . Framework ;
6
+ using Microsoft . Build . Logging ;
6
7
using Microsoft . DotNet . Cli . Commands . MSBuild ;
7
8
8
9
namespace Microsoft . DotNet . Cli . Extensions ;
@@ -51,17 +52,18 @@ public static IEnumerable<string> GetConfigurations(this ProjectInstance project
51
52
}
52
53
53
54
/// <summary>
54
- /// Creates telemetry loggers for API-based MSBuild usage if telemetry is enabled.
55
- /// Returns null if telemetry is not enabled or if there's an error creating the loggers.
55
+ /// Creates the central telemetry logger for API-based MSBuild usage if telemetry is enabled.
56
+ /// This logger should be used for evaluation (ProjectCollection) and as a central logger for builds.
57
+ /// Returns null if telemetry is not enabled or if there's an error creating the logger.
56
58
/// </summary>
57
- /// <returns>A list of loggers to use with ProjectInstance.Build , or null if telemetry is disabled.</returns>
58
- public static ILogger [ ] ? CreateTelemetryLoggers ( )
59
+ /// <returns>The central telemetry logger , or null if telemetry is disabled.</returns>
60
+ public static ILogger ? CreateTelemetryCentralLogger ( )
59
61
{
60
62
if ( Telemetry . Telemetry . CurrentSessionId != null )
61
63
{
62
64
try
63
65
{
64
- return [ new MSBuildLogger ( ) ] ;
66
+ return new MSBuildLogger ( ) ;
65
67
}
66
68
catch ( Exception )
67
69
{
@@ -72,32 +74,72 @@ public static IEnumerable<string> GetConfigurations(this ProjectInstance project
72
74
}
73
75
74
76
/// <summary>
75
- /// Builds the project with the specified targets, automatically including telemetry loggers.
77
+ /// Creates the forwarding logger record for distributed builds if telemetry is enabled.
78
+ /// This should be used with the remoteLoggers parameter of ProjectInstance.Build.
79
+ /// Returns an empty collection if telemetry is not enabled or if there's an error creating the logger.
80
+ /// </summary>
81
+ /// <returns>An array containing the forwarding logger record, or empty array if telemetry is disabled.</returns>
82
+ public static ForwardingLoggerRecord [ ] CreateTelemetryForwardingLoggerRecords ( )
83
+ {
84
+ if ( Telemetry . Telemetry . CurrentSessionId != null )
85
+ {
86
+ try
87
+ {
88
+ var forwardingLogger = new MSBuildForwardingLogger ( ) ;
89
+ var loggerRecord = new ForwardingLoggerRecord ( forwardingLogger , new Microsoft . Build . Logging . LoggerDescription (
90
+ loggerClassName : typeof ( MSBuildLogger ) . FullName ! ,
91
+ loggerAssemblyName : typeof ( MSBuildLogger ) . Assembly . Location ,
92
+ loggerAssemblyFile : null ,
93
+ loggerSwitchParameters : null ,
94
+ verbosity : LoggerVerbosity . Normal ) ) ;
95
+ return [ loggerRecord ] ;
96
+ }
97
+ catch ( Exception )
98
+ {
99
+ // Exceptions during telemetry shouldn't cause anything else to fail
100
+ }
101
+ }
102
+ return [ ] ;
103
+ }
104
+
105
+ /// <summary>
106
+ /// Builds the project with the specified targets, automatically including telemetry loggers
107
+ /// as a distributed logger (central logger + forwarding logger).
76
108
/// </summary>
77
109
public static bool BuildWithTelemetry (
78
110
this ProjectInstance projectInstance ,
79
111
string [ ] targets ,
80
112
IEnumerable < ILogger > ? additionalLoggers = null )
81
113
{
82
114
var loggers = new List < ILogger > ( ) ;
115
+ var forwardingLoggers = new List < ForwardingLoggerRecord > ( ) ;
83
116
84
- var telemetryLoggers = CreateTelemetryLoggers ( ) ;
85
- if ( telemetryLoggers != null )
117
+ // Add central telemetry logger
118
+ var telemetryCentralLogger = CreateTelemetryCentralLogger ( ) ;
119
+ if ( telemetryCentralLogger != null )
86
120
{
87
- loggers . AddRange ( telemetryLoggers ) ;
121
+ loggers . Add ( telemetryCentralLogger ) ;
122
+
123
+ // Add forwarding logger for distributed builds
124
+ forwardingLoggers . AddRange ( CreateTelemetryForwardingLoggerRecords ( ) ) ;
88
125
}
89
126
90
127
if ( additionalLoggers != null )
91
128
{
92
129
loggers . AddRange ( additionalLoggers ) ;
93
130
}
94
131
95
- return projectInstance . Build ( targets , loggers . Count > 0 ? loggers : null ) ;
132
+ // Use the overload that accepts forwarding loggers for proper distributed logging
133
+ return projectInstance . Build (
134
+ targets ,
135
+ loggers . Count > 0 ? loggers : null ,
136
+ forwardingLoggers . Count > 0 ? forwardingLoggers : null ,
137
+ out _ ) ;
96
138
}
97
139
98
140
/// <summary>
99
- /// Builds the project with the specified targets, automatically including telemetry loggers.
100
- /// Overload for Build with targetOutputs parameter .
141
+ /// Builds the project with the specified targets, automatically including telemetry loggers
142
+ /// as a distributed logger (central logger + forwarding logger) .
101
143
/// </summary>
102
144
public static bool BuildWithTelemetry (
103
145
this ProjectInstance projectInstance ,
@@ -106,45 +148,94 @@ public static bool BuildWithTelemetry(
106
148
out IDictionary < string , TargetResult > targetOutputs )
107
149
{
108
150
var allLoggers = new List < ILogger > ( ) ;
151
+ var forwardingLoggers = new List < ForwardingLoggerRecord > ( ) ;
109
152
110
- var telemetryLoggers = CreateTelemetryLoggers ( ) ;
111
- if ( telemetryLoggers != null )
153
+ // Add central telemetry logger
154
+ var telemetryCentralLogger = CreateTelemetryCentralLogger ( ) ;
155
+ if ( telemetryCentralLogger != null )
112
156
{
113
- allLoggers . AddRange ( telemetryLoggers ) ;
157
+ allLoggers . Add ( telemetryCentralLogger ) ;
158
+
159
+ // Add forwarding logger for distributed builds
160
+ forwardingLoggers . AddRange ( CreateTelemetryForwardingLoggerRecords ( ) ) ;
114
161
}
115
162
116
163
if ( loggers != null )
117
164
{
118
165
allLoggers . AddRange ( loggers ) ;
119
166
}
120
167
121
- return projectInstance . Build ( targets , allLoggers . Count > 0 ? allLoggers : null , out targetOutputs ) ;
168
+ // Use the overload that accepts forwarding loggers for proper distributed logging
169
+ return projectInstance . Build (
170
+ targets ,
171
+ allLoggers . Count > 0 ? allLoggers : null ,
172
+ forwardingLoggers . Count > 0 ? forwardingLoggers : null ,
173
+ out targetOutputs ) ;
122
174
}
123
175
124
176
/// <summary>
125
- /// Builds the project with the specified targets, automatically including telemetry loggers.
126
- /// Overload for Build with loggers, remoteLoggers, and targetOutputs parameters .
177
+ /// Builds the project with the specified targets, automatically including telemetry loggers
178
+ /// as a distributed logger (central logger + forwarding logger) .
127
179
/// </summary>
128
180
public static bool BuildWithTelemetry (
129
181
this ProjectInstance projectInstance ,
130
182
string [ ] targets ,
131
183
IEnumerable < ILogger > ? loggers ,
132
- IEnumerable < Microsoft . Build . Logging . ForwardingLoggerRecord > ? remoteLoggers ,
184
+ IEnumerable < ForwardingLoggerRecord > ? remoteLoggers ,
133
185
out IDictionary < string , TargetResult > targetOutputs )
134
186
{
135
187
var allLoggers = new List < ILogger > ( ) ;
188
+ var allForwardingLoggers = new List < ForwardingLoggerRecord > ( ) ;
136
189
137
- var telemetryLoggers = CreateTelemetryLoggers ( ) ;
138
- if ( telemetryLoggers != null )
190
+ // Add central telemetry logger
191
+ var telemetryCentralLogger = CreateTelemetryCentralLogger ( ) ;
192
+ if ( telemetryCentralLogger != null )
139
193
{
140
- allLoggers . AddRange ( telemetryLoggers ) ;
194
+ allLoggers . Add ( telemetryCentralLogger ) ;
195
+
196
+ // Add forwarding logger for distributed builds
197
+ allForwardingLoggers . AddRange ( CreateTelemetryForwardingLoggerRecords ( ) ) ;
141
198
}
142
199
143
200
if ( loggers != null )
144
201
{
145
202
allLoggers . AddRange ( loggers ) ;
146
203
}
147
204
148
- return projectInstance . Build ( targets , allLoggers . Count > 0 ? allLoggers : null , remoteLoggers , out targetOutputs ) ;
205
+ if ( remoteLoggers != null )
206
+ {
207
+ allForwardingLoggers . AddRange ( remoteLoggers ) ;
208
+ }
209
+
210
+ return projectInstance . Build (
211
+ targets ,
212
+ allLoggers . Count > 0 ? allLoggers : null ,
213
+ allForwardingLoggers . Count > 0 ? allForwardingLoggers : null ,
214
+ out targetOutputs ) ;
215
+ }
216
+
217
+ /// <summary>
218
+ /// Creates a logger collection that includes the telemetry central logger.
219
+ /// This is useful for ProjectCollection scenarios where evaluation needs telemetry.
220
+ /// </summary>
221
+ /// <param name="additionalLoggers">Additional loggers to include in the collection.</param>
222
+ /// <returns>An array of loggers including telemetry logger if enabled, or null if no loggers.</returns>
223
+ public static ILogger [ ] ? CreateLoggersWithTelemetry ( IEnumerable < ILogger > ? additionalLoggers = null )
224
+ {
225
+ var loggers = new List < ILogger > ( ) ;
226
+
227
+ // Add central telemetry logger for evaluation
228
+ var telemetryCentralLogger = CreateTelemetryCentralLogger ( ) ;
229
+ if ( telemetryCentralLogger != null )
230
+ {
231
+ loggers . Add ( telemetryCentralLogger ) ;
232
+ }
233
+
234
+ if ( additionalLoggers != null )
235
+ {
236
+ loggers . AddRange ( additionalLoggers ) ;
237
+ }
238
+
239
+ return loggers . Count > 0 ? loggers . ToArray ( ) : null ;
149
240
}
150
241
}
0 commit comments