[analytics] process and propagate analytics ENV context
Fixes: https://github.com/dart-lang/sdk/issues/62875 Bug: https://github.com/dart-lang/sdk/issues/62875 Change-Id: I864c2fb401dd2eb9859b1277ea971db758ace618 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/488583 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Phil Quitslund <pquitslund@google.com>
This commit is contained in:
@@ -312,6 +312,7 @@ abstract class AnalysisServer {
|
||||
MessageSchedulerListener? messageSchedulerListener,
|
||||
this.performanceLogger,
|
||||
required bool usePlugins,
|
||||
Map<String, String>? environment,
|
||||
}) : resourceProvider = OverlayResourceProvider(baseResourceProvider),
|
||||
pubApi = PubApi(
|
||||
instrumentationService,
|
||||
@@ -333,7 +334,7 @@ abstract class AnalysisServer {
|
||||
// don't really exist. If processRunner was supplied, it's likely a mock
|
||||
// from a test in which case the pub command should still be created.
|
||||
if (baseResourceProvider is PhysicalResourceProvider) {
|
||||
processRunner ??= ProcessRunner();
|
||||
processRunner ??= ProcessRunner(environment: environment);
|
||||
}
|
||||
var disablePubCommandVariable =
|
||||
platform.environment[PubCommand.disablePubCommandEnvironmentKey];
|
||||
@@ -360,6 +361,7 @@ abstract class AnalysisServer {
|
||||
notificationManager,
|
||||
instrumentationService,
|
||||
sessionLogger,
|
||||
processRunner: processRunner ?? ProcessRunner(environment: environment),
|
||||
);
|
||||
var pluginWatcher = PluginWatcher(
|
||||
resourceProvider,
|
||||
|
||||
@@ -402,6 +402,7 @@ class LegacyAnalysisServer extends AnalysisServer {
|
||||
super.pluginManager,
|
||||
super.messageSchedulerListener,
|
||||
PerformanceLogger? performanceLogger,
|
||||
super.environment,
|
||||
}) : lspClientConfiguration = lsp.LspClientConfiguration(
|
||||
baseResourceProvider.pathContext,
|
||||
),
|
||||
|
||||
@@ -149,6 +149,7 @@ class LspAnalysisServer extends AnalysisServer {
|
||||
super.dartFixPromptManager,
|
||||
super.messageSchedulerListener,
|
||||
super.performanceLogger,
|
||||
super.environment,
|
||||
}) : lspClientConfiguration = LspClientConfiguration(
|
||||
baseResourceProvider.pathContext,
|
||||
),
|
||||
|
||||
@@ -52,6 +52,8 @@ class LspSocketServer implements AbstractSocketServer {
|
||||
/// The performance logger.
|
||||
final PerformanceLogger? performanceLogger;
|
||||
|
||||
final Map<String, String>? environment;
|
||||
|
||||
LspSocketServer(
|
||||
this.analysisServerOptions,
|
||||
this.diagnosticServer,
|
||||
@@ -60,8 +62,9 @@ class LspSocketServer implements AbstractSocketServer {
|
||||
this.instrumentationService,
|
||||
this.sessionLogger,
|
||||
this.detachableFileSystemManager,
|
||||
this.performanceLogger,
|
||||
);
|
||||
this.performanceLogger, {
|
||||
this.environment,
|
||||
});
|
||||
|
||||
/// Create an analysis server which will communicate with the client using the
|
||||
/// given serverChannel.
|
||||
@@ -112,6 +115,7 @@ class LspSocketServer implements AbstractSocketServer {
|
||||
detachableFileSystemManager: detachableFileSystemManager,
|
||||
enableBlazeWatcher: true,
|
||||
performanceLogger: performanceLogger,
|
||||
environment: environment,
|
||||
);
|
||||
detachableFileSystemManager?.setAnalysisServer(server);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import 'package:analysis_server/src/services/perf_witness/perf_witness.dart';
|
||||
import 'package:analysis_server/src/session_logger/session_logger.dart';
|
||||
import 'package:analysis_server/src/socket_server.dart';
|
||||
import 'package:analysis_server/src/status/performance_logger.dart';
|
||||
import 'package:analysis_server/src/utilities/env.dart' as env;
|
||||
import 'package:analysis_server/src/utilities/request_statistics.dart';
|
||||
import 'package:analysis_server/starter.dart';
|
||||
import 'package:analyzer/file_system/physical_file_system.dart';
|
||||
@@ -227,13 +228,6 @@ class Driver implements ServerStarter {
|
||||
|
||||
analysisServerOptions.usePlugins = results.flag(pluginsFlag);
|
||||
|
||||
// Analytics (legacy, and unified)
|
||||
var disableAnalyticsForSession = results.flag(suppressAnalyticsFlag);
|
||||
|
||||
if (results.wasParsed(trainUsingOption)) {
|
||||
disableAnalyticsForSession = true;
|
||||
}
|
||||
|
||||
var defaultSdkPath = _getSdkPath(results);
|
||||
var dartSdkManager = DartSdkManager(defaultSdkPath);
|
||||
|
||||
@@ -243,22 +237,26 @@ class Driver implements ServerStarter {
|
||||
var defaultSdk = _createDefaultSdk(defaultSdkPath);
|
||||
|
||||
// Create the analytics manager.
|
||||
Analytics analytics;
|
||||
if (disableAnalyticsForSession) {
|
||||
analytics = NoOpAnalytics();
|
||||
} else {
|
||||
var tool = switch (clientId) {
|
||||
'VS-Code' || 'VS-Code-Remote' => DashTool.vscodePlugins,
|
||||
'IntelliJ-IDEA' => DashTool.intellijPlugins,
|
||||
'Android-Studio' => DashTool.androidStudioPlugins,
|
||||
_ => null,
|
||||
};
|
||||
if (tool != null) {
|
||||
analytics = _createAnalytics(defaultSdk, defaultSdkPath, tool);
|
||||
} else {
|
||||
analytics = NoOpAnalytics();
|
||||
}
|
||||
}
|
||||
|
||||
var tool =
|
||||
env.topLevelTool ??
|
||||
switch (clientId) {
|
||||
'VS-Code' || 'VS-Code-Remote' => DashTool.vscodePlugins,
|
||||
'IntelliJ-IDEA' => DashTool.intellijPlugins,
|
||||
'Android-Studio' => DashTool.androidStudioPlugins,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
// Analytics (legacy, and unified).
|
||||
var disableAnalyticsForSession =
|
||||
tool == null ||
|
||||
areAnalyticsSuppressed() ||
|
||||
results.flag(suppressAnalyticsFlag) ||
|
||||
results.wasParsed(trainUsingOption);
|
||||
|
||||
var analytics = disableAnalyticsForSession
|
||||
? NoOpAnalytics()
|
||||
: _createAnalytics(defaultSdk, defaultSdkPath, tool);
|
||||
var analyticsManager = AnalyticsManager(analytics);
|
||||
|
||||
bool shouldSendCallback() {
|
||||
@@ -375,6 +373,12 @@ class Driver implements ServerStarter {
|
||||
// TODO(brianwilkerson): Pass the following value to the server and
|
||||
// implement the debouncing when it hasn't been disabled.
|
||||
// var disableDebouncing = results[DISABLE_STATUS_NOTIFICATION_DEBOUNCING] as bool;
|
||||
|
||||
var environment = env.map(
|
||||
tool: tool,
|
||||
suppressAnalytics: disableAnalyticsForSession,
|
||||
);
|
||||
|
||||
if (analysisServerOptions.useLanguageServerProtocol) {
|
||||
if (sendPort != null) {
|
||||
throw UnimplementedError(
|
||||
@@ -391,6 +395,7 @@ class Driver implements ServerStarter {
|
||||
diagnosticServerPort,
|
||||
errorNotifier,
|
||||
performanceLogger,
|
||||
environment,
|
||||
);
|
||||
} else {
|
||||
startAnalysisServer(
|
||||
@@ -407,6 +412,7 @@ class Driver implements ServerStarter {
|
||||
errorNotifier,
|
||||
sendPort,
|
||||
performanceLogger,
|
||||
environment,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -430,6 +436,7 @@ class Driver implements ServerStarter {
|
||||
ErrorNotifier errorNotifier,
|
||||
SendPort? sendPort,
|
||||
PerformanceLogger? performanceLogger,
|
||||
Map<String, String>? environment,
|
||||
) {
|
||||
var capture = results.flag(disableServerExceptionHandlingOption)
|
||||
? (_, Function f, {void Function(String)? print}) => f()
|
||||
@@ -462,6 +469,7 @@ class Driver implements ServerStarter {
|
||||
analyticsManager,
|
||||
detachableFileSystemManager,
|
||||
performanceLogger,
|
||||
environment: environment,
|
||||
);
|
||||
|
||||
diagnosticServer.httpServer = HttpAnalysisServer(socketServer);
|
||||
@@ -551,6 +559,7 @@ class Driver implements ServerStarter {
|
||||
int? diagnosticServerPort,
|
||||
ErrorNotifier errorNotifier,
|
||||
PerformanceLogger? performanceLogger,
|
||||
Map<String, String>? environment,
|
||||
) {
|
||||
var capture = args.flag(disableServerExceptionHandlingOption)
|
||||
? (_, Function f, {void Function(String)? print}) => f()
|
||||
@@ -571,6 +580,7 @@ class Driver implements ServerStarter {
|
||||
sessionLogger,
|
||||
detachableFileSystemManager,
|
||||
performanceLogger,
|
||||
environment: environment,
|
||||
);
|
||||
errorNotifier.server = socketServer.analysisServer;
|
||||
diagnosticServer.httpServer = HttpAnalysisServer(socketServer);
|
||||
|
||||
@@ -64,6 +64,8 @@ class SocketServer implements AbstractSocketServer {
|
||||
/// The performance logger.
|
||||
final PerformanceLogger? performanceLogger;
|
||||
|
||||
final Map<String, String>? environment;
|
||||
|
||||
SocketServer(
|
||||
this.analysisServerOptions,
|
||||
this.sdkManager,
|
||||
@@ -74,8 +76,9 @@ class SocketServer implements AbstractSocketServer {
|
||||
this.diagnosticServer,
|
||||
this.analyticsManager,
|
||||
this.detachableFileSystemManager,
|
||||
this.performanceLogger,
|
||||
);
|
||||
this.performanceLogger, {
|
||||
this.environment,
|
||||
});
|
||||
|
||||
/// Create an analysis server which will communicate with the client using the
|
||||
/// given serverChannel.
|
||||
@@ -112,6 +115,7 @@ class SocketServer implements AbstractSocketServer {
|
||||
detachableFileSystemManager: detachableFileSystemManager,
|
||||
enableBlazeWatcher: true,
|
||||
performanceLogger: performanceLogger,
|
||||
environment: environment,
|
||||
);
|
||||
detachableFileSystemManager?.setAnalysisServer(server);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:platform/platform.dart' as platform;
|
||||
import 'package:unified_analytics/unified_analytics.dart';
|
||||
|
||||
DashTool? get topLevelTool {
|
||||
var toolValue = _readEnv(DashEnvVar.tool.name);
|
||||
if (toolValue != null) {
|
||||
try {
|
||||
return DashTool.fromLabel(toolValue);
|
||||
} on Exception {
|
||||
// Unsupported tools are skipped.
|
||||
// We could consider logging or crash-reporting but we can't collect
|
||||
// analytics since telemetry for an unknown tool can't be opted into.
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, String> get _locaEnvironment =>
|
||||
const platform.LocalPlatform().environment;
|
||||
|
||||
/// Returns a copy of the current environment with the given analytics values set.
|
||||
Map<String, String> map({
|
||||
required DashTool? tool,
|
||||
required bool suppressAnalytics,
|
||||
}) => <String, String>{
|
||||
..._locaEnvironment,
|
||||
DashEnvVar.suppressAnalytics.name: suppressAnalytics.toString(),
|
||||
if (tool != null) DashEnvVar.tool.name: tool.label,
|
||||
};
|
||||
|
||||
String? _readEnv(String key) => _locaEnvironment[key];
|
||||
@@ -8,7 +8,9 @@ import 'dart:io';
|
||||
|
||||
/// An abstraction over [Process] from 'dart:io' to allow mocking in tests.
|
||||
class ProcessRunner {
|
||||
const ProcessRunner();
|
||||
final Map<String, String>? environment;
|
||||
|
||||
const ProcessRunner({this.environment});
|
||||
|
||||
ProcessResult runSync(
|
||||
String executable,
|
||||
@@ -17,14 +19,16 @@ class ProcessRunner {
|
||||
Map<String, String>? environment,
|
||||
Encoding? stderrEncoding,
|
||||
Encoding? stdoutEncoding,
|
||||
}) => Process.runSync(
|
||||
executable,
|
||||
arguments,
|
||||
workingDirectory: workingDirectory,
|
||||
environment: environment,
|
||||
stderrEncoding: stderrEncoding,
|
||||
stdoutEncoding: stdoutEncoding,
|
||||
);
|
||||
}) {
|
||||
return Process.runSync(
|
||||
executable,
|
||||
arguments,
|
||||
workingDirectory: workingDirectory,
|
||||
environment: _mergedEnv(environment),
|
||||
stderrEncoding: stderrEncoding,
|
||||
stdoutEncoding: stdoutEncoding,
|
||||
);
|
||||
}
|
||||
|
||||
Future<Process> start(
|
||||
String executable,
|
||||
@@ -39,10 +43,15 @@ class ProcessRunner {
|
||||
executable,
|
||||
arguments,
|
||||
workingDirectory: workingDirectory,
|
||||
environment: environment,
|
||||
environment: _mergedEnv(environment),
|
||||
includeParentEnvironment: includeParentEnvironment,
|
||||
runInShell: runInShell,
|
||||
mode: mode,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, String>? _mergedEnv(Map<String, String>? environment) {
|
||||
var merged = <String, String>{...?this.environment, ...?environment};
|
||||
return merged.isNotEmpty ? merged : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ dependencies:
|
||||
meta: any
|
||||
path: any
|
||||
perf_witness: any
|
||||
platform: any
|
||||
pub_semver: any
|
||||
stream_channel: any
|
||||
telemetry: any
|
||||
|
||||
@@ -92,6 +92,9 @@ class MockProcess implements Process {
|
||||
}
|
||||
|
||||
class MockProcessRunner implements ProcessRunner {
|
||||
@override
|
||||
final Map<String, String>? environment = null;
|
||||
|
||||
ProcessResult Function(
|
||||
String executable,
|
||||
List<String> arguments, {
|
||||
|
||||
Reference in New Issue
Block a user