diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs index 7b249f0517..8ff8ad3206 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs @@ -1,5 +1,8 @@ +using System; +using System.Linq; using System.Text; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Volo.Abp.Cli.Commands; using Volo.Abp.Cli.Commands.Internal; using Volo.Abp.Cli.Http; @@ -7,9 +10,12 @@ using Volo.Abp.Cli.ServiceProxying; using Volo.Abp.Cli.ServiceProxying.Angular; using Volo.Abp.Cli.ServiceProxying.CSharp; using Volo.Abp.Cli.ServiceProxying.JavaScript; +using Volo.Abp.Cli.Telemetry; using Volo.Abp.Domain; using Volo.Abp.Http; using Volo.Abp.IdentityModel; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Activity.Providers; using Volo.Abp.Json; using Volo.Abp.Localization; using Volo.Abp.Minify; @@ -27,6 +33,8 @@ namespace Volo.Abp.Cli; )] public class AbpCliCoreModule : AbpModule { + private const string EnableTelemetryVariableName = "ABP_STUDIO_ENABLE_TELEMETRY"; + public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddHttpClient(CliConsts.HttpClientName) @@ -82,5 +90,23 @@ public class AbpCliCoreModule : AbpModule options.Generators[AngularServiceProxyGenerator.Name] = typeof(AngularServiceProxyGenerator); options.Generators[CSharpServiceProxyGenerator.Name] = typeof(CSharpServiceProxyGenerator); }); + + ConfigureTelemetry(context.Services); + } + + private static void ConfigureTelemetry(IServiceCollection services) + { + var enableTelemetryEnvironmentVariable = Environment.GetEnvironmentVariable(EnableTelemetryVariableName , EnvironmentVariableTarget.Machine) + ?? Environment.GetEnvironmentVariable(EnableTelemetryVariableName , EnvironmentVariableTarget.User) + ?? Environment.GetEnvironmentVariable(EnableTelemetryVariableName , EnvironmentVariableTarget.Process); + + if (enableTelemetryEnvironmentVariable.IsNullOrEmpty() || !enableTelemetryEnvironmentVariable.Equals("false", StringComparison.InvariantCultureIgnoreCase)) + { + services.Remove(services.First(p => p.ImplementationType == typeof(TelemetrySessionInfoEnricher))); + } + else + { + services.Replace(ServiceDescriptor.Singleton()); + } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs index 0a0c46b6a4..063ceddebf 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs @@ -14,12 +14,15 @@ using Volo.Abp.Cli.Memory; using Volo.Abp.Cli.Version; using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Constants; namespace Volo.Abp.Cli; public class CliService : ITransientDependency { private readonly MemoryService _memoryService; + private readonly ITelemetryService _telemetryService; public ILogger Logger { get; set; } protected ICommandLineArgumentParser CommandLineArgumentParser { get; } protected ICommandSelector CommandSelector { get; } @@ -35,7 +38,8 @@ public class CliService : ITransientDependency PackageVersionCheckerService nugetService, ICmdHelper cmdHelper, MemoryService memoryService, - CliVersionService cliVersionService) + CliVersionService cliVersionService, + ITelemetryService telemetryService) { _memoryService = memoryService; CommandLineArgumentParser = commandLineArgumentParser; @@ -44,6 +48,7 @@ public class CliService : ITransientDependency PackageVersionCheckerService = nugetService; CmdHelper = cmdHelper; CliVersionService = cliVersionService; + _telemetryService = telemetryService; Logger = NullLogger.Instance; } @@ -64,6 +69,7 @@ public class CliService : ITransientDependency try { + await using var _ = _telemetryService.TrackActivityAsync(ActivityNameConsts.AbpCliRun); if (commandLineArgs.IsCommand("prompt")) { await RunPromptAsync(); @@ -84,9 +90,14 @@ public class CliService : ITransientDependency } catch (Exception ex) { + await _telemetryService.AddErrorActivityAsync(ex.Message); Logger.LogException(ex); throw; } + finally + { + await _telemetryService.AddActivityAsync(ActivityNameConsts.AbpCliExit); + } } private async Task RunPromptAsync() diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs index 4756c3f99b..38483517da 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs @@ -11,6 +11,8 @@ using Volo.Abp.Cli.ProjectBuilding.Templates.MvcModule; using Volo.Abp.Cli.ProjectModification; using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Constants; namespace Volo.Abp.Cli.Commands; @@ -20,6 +22,8 @@ public class AddModuleCommand : IConsoleCommand, ITransientDependency public const string Name = "add-module"; private AddModuleInfoOutput _lastAddedModuleInfo; + private readonly ITelemetryService _telemetryService; + public ILogger Logger { get; set; } protected SolutionModuleAdder SolutionModuleAdder { get; } @@ -39,11 +43,13 @@ public class AddModuleCommand : IConsoleCommand, ITransientDependency public AddModuleCommand( SolutionModuleAdder solutionModuleAdder, SolutionPackageVersionFinder solutionPackageVersionFinder, - IOptions options) + IOptions options, + ITelemetryService telemetryService) { _options = options.Value; SolutionModuleAdder = solutionModuleAdder; SolutionPackageVersionFinder = solutionPackageVersionFinder; + _telemetryService = telemetryService; Logger = NullLogger.Instance; } @@ -66,6 +72,11 @@ public class AddModuleCommand : IConsoleCommand, ITransientDependency } var newTemplate = commandLineArgs.Options.ContainsKey(Options.NewTemplate.Long); + + await using var _ = _telemetryService.TrackActivityAsync(newTemplate + ? ActivityNameConsts.AbpCliCommandsInstallLocalModule + : ActivityNameConsts.AbpCliCommandsInstallModule); + var template = commandLineArgs.Options.GetOrNull(Options.Template.Short, Options.Template.Long); var newProTemplate = !string.IsNullOrEmpty(template) && template == ModuleProTemplate.TemplateName; var withSourceCode = newTemplate || newProTemplate || commandLineArgs.Options.ContainsKey(Options.SourceCode.Long); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs index e9acb7ae24..f397ef8d6e 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs @@ -9,6 +9,8 @@ using Volo.Abp.Cli.Args; using Volo.Abp.Cli.ProjectModification; using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Constants; namespace Volo.Abp.Cli.Commands; @@ -16,16 +18,19 @@ public class AddPackageCommand : IConsoleCommand, ITransientDependency { public const string Name = "add-package"; + private readonly ITelemetryService _telemetryService; + public ILogger Logger { get; set; } protected ProjectNugetPackageAdder ProjectNugetPackageAdder { get; } public ProjectNpmPackageAdder ProjectNpmPackageAdder { get; } - public AddPackageCommand(ProjectNugetPackageAdder projectNugetPackageAdder, ProjectNpmPackageAdder projectNpmPackageAdder) + public AddPackageCommand(ProjectNugetPackageAdder projectNugetPackageAdder, ProjectNpmPackageAdder projectNpmPackageAdder, ITelemetryService telemetryService) { ProjectNugetPackageAdder = projectNugetPackageAdder; ProjectNpmPackageAdder = projectNpmPackageAdder; + _telemetryService = telemetryService; Logger = NullLogger.Instance; } @@ -39,6 +44,9 @@ public class AddPackageCommand : IConsoleCommand, ITransientDependency GetUsageInfo() ); } + + await using var _ = _telemetryService.TrackActivityAsync(ActivityNameConsts.AbpCliCommandsNewPackage); + await using var __ = _telemetryService.TrackActivityAsync(ActivityNameConsts.AbpCliCommandsAddPackage); var isNpmPackage = false; var isNugetPackage = true; @@ -51,11 +59,11 @@ public class AddPackageCommand : IConsoleCommand, ITransientDependency var version = commandLineArgs.Options.GetOrNull(Options.Version.Short, Options.Version.Long); var withSourceCode = commandLineArgs.Options.ContainsKey(Options.SourceCode.Long); - + if (isNugetPackage) { var addSourceCodeToSolutionFile = withSourceCode && commandLineArgs.Options.ContainsKey("add-to-solution-file"); - + await ProjectNugetPackageAdder.AddAsync( GetSolutionFile(commandLineArgs), GetProjectFile(commandLineArgs), diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CleanCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CleanCommand.cs index 092e996095..661cf7995b 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CleanCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CleanCommand.cs @@ -8,6 +8,8 @@ using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Cli.Args; using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Constants; namespace Volo.Abp.Cli.Commands; @@ -16,17 +18,21 @@ public class CleanCommand : IConsoleCommand, ITransientDependency public const string Name = "clean"; public ILogger Logger { get; set; } - + protected ICmdHelper CmdHelper { get; } + + private readonly ITelemetryService _telemetryService; - public CleanCommand(ICmdHelper cmdHelper) + public CleanCommand(ICmdHelper cmdHelper, ITelemetryService telemetryService) { CmdHelper = cmdHelper; + _telemetryService = telemetryService; Logger = NullLogger.Instance; } - public Task ExecuteAsync(CommandLineArgs commandLineArgs) + public async Task ExecuteAsync(CommandLineArgs commandLineArgs) { + await using var _ = _telemetryService.TrackActivityAsync(ActivityNameConsts.AbpCliCommandsClean); var binEntries = Directory.EnumerateDirectories(Directory.GetCurrentDirectory(), "bin", SearchOption.AllDirectories); var objEntries = Directory.EnumerateDirectories(Directory.GetCurrentDirectory(), "obj", SearchOption.AllDirectories); @@ -49,7 +55,6 @@ public class CleanCommand : IConsoleCommand, ITransientDependency Logger.LogInformation($"'bin' and 'obj' folders removed successfully!"); Logger.LogInformation("Solution cleaned successfully!"); - return Task.CompletedTask; } public string GetUsageInfo() diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ListModulesCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ListModulesCommand.cs index af685102d8..8a9d4fd6d1 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ListModulesCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ListModulesCommand.cs @@ -7,6 +7,8 @@ using System.Threading.Tasks; using Volo.Abp.Cli.Args; using Volo.Abp.Cli.ProjectBuilding; using Volo.Abp.DependencyInjection; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Constants; namespace Volo.Abp.Cli.Commands; @@ -17,15 +19,19 @@ public class ListModulesCommand : IConsoleCommand, ITransientDependency public ModuleInfoProvider ModuleInfoProvider { get; } public ILogger Logger { get; set; } + private readonly ITelemetryService _telemetryService; - public ListModulesCommand(ModuleInfoProvider moduleInfoProvider) + public ListModulesCommand(ModuleInfoProvider moduleInfoProvider, ITelemetryService telemetryService) { ModuleInfoProvider = moduleInfoProvider; + _telemetryService = telemetryService; Logger = NullLogger.Instance; } public async Task ExecuteAsync(CommandLineArgs commandLineArgs) { + await using var _ = _telemetryService.TrackActivityAsync(ActivityNameConsts.AbpCliCommandsListModules); + var modules = await ModuleInfoProvider.GetModuleListAsync(); var freeModules = modules.Where(m => !m.IsPro).ToList(); var proModules = modules.Where(m => m.IsPro).ToList(); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs index 796a8ff757..149b477d5b 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs @@ -11,11 +11,15 @@ using Volo.Abp.Cli.Commands.Services; using Volo.Abp.Cli.LIbs; using Volo.Abp.Cli.ProjectBuilding; using Volo.Abp.Cli.ProjectBuilding.Events; +using Volo.Abp.Cli.ProjectBuilding.Templates.Module; using Volo.Abp.Cli.ProjectModification; using Volo.Abp.Cli.Utils; using Volo.Abp.Cli.Version; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Local; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Constants; +using Volo.Abp.Internal.Telemetry.Constants.Enums; namespace Volo.Abp.Cli.Commands; @@ -26,6 +30,8 @@ public class NewCommand : ProjectCreationCommandBase, IConsoleCommand, ITransien protected TemplateProjectBuilder TemplateProjectBuilder { get; } public ITemplateInfoProvider TemplateInfoProvider { get; } + private readonly ITelemetryService _telemetryService; + public NewCommand( ConnectionStringProvider connectionStringProvider, SolutionPackageVersionFinder solutionPackageVersionFinder, @@ -40,7 +46,8 @@ public class NewCommand : ProjectCreationCommandBase, IConsoleCommand, ITransien ITemplateInfoProvider templateInfoProvider, TemplateProjectBuilder templateProjectBuilder, AngularThemeConfigurer angularThemeConfigurer, - CliVersionService cliVersionService) : + CliVersionService cliVersionService, + ITelemetryService telemetryService) : base(connectionStringProvider, solutionPackageVersionFinder, cmdHelper, @@ -56,6 +63,7 @@ public class NewCommand : ProjectCreationCommandBase, IConsoleCommand, ITransien { TemplateInfoProvider = templateInfoProvider; TemplateProjectBuilder = templateProjectBuilder; + _telemetryService = telemetryService; } public async Task ExecuteAsync(CommandLineArgs commandLineArgs) @@ -94,6 +102,19 @@ public class NewCommand : ProjectCreationCommandBase, IConsoleCommand, ITransien var result = await TemplateProjectBuilder.BuildAsync( projectArgs ); + + var activityName = ActivityNameConsts.AbpCliCommandsNewSolution; + + if (ModuleTemplateBase.IsModuleTemplate(template)) + { + activityName = ActivityNameConsts.AbpCliCommandsNewModule; + } + + await _telemetryService.AddActivityAsync(activityName, o => + { + o[ActivityPropertyNames.CreationTool] = AbpTool.OldCli; + o[ActivityPropertyNames.Template] = template; + }); ExtractProjectZip(result, projectArgs.OutputFolder); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs index ae3cda8723..68ab346064 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs @@ -9,6 +9,8 @@ using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Cli.Args; using Volo.Abp.Cli.ProjectModification; using Volo.Abp.DependencyInjection; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Constants; namespace Volo.Abp.Cli.Commands; @@ -20,18 +22,21 @@ public class UpdateCommand : IConsoleCommand, ITransientDependency private readonly VoloNugetPackagesVersionUpdater _nugetPackagesVersionUpdater; private readonly NpmPackagesUpdater _npmPackagesUpdater; + private readonly ITelemetryService _telemetryService; public UpdateCommand(VoloNugetPackagesVersionUpdater nugetPackagesVersionUpdater, - NpmPackagesUpdater npmPackagesUpdater) + NpmPackagesUpdater npmPackagesUpdater, ITelemetryService telemetryService) { _nugetPackagesVersionUpdater = nugetPackagesVersionUpdater; _npmPackagesUpdater = npmPackagesUpdater; + _telemetryService = telemetryService; Logger = NullLogger.Instance; } public async Task ExecuteAsync(CommandLineArgs commandLineArgs) { + await using var _ = _telemetryService.TrackActivityAsync(ActivityNameConsts.AbpCliCommandsUpdate); var updateNpm = commandLineArgs.Options.ContainsKey(Options.Packages.Npm); var updateNuget = commandLineArgs.Options.ContainsKey(Options.Packages.NuGet); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Telemetry/NullTelemetryService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Telemetry/NullTelemetryService.cs new file mode 100644 index 0000000000..4f3c695f7d --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Telemetry/NullTelemetryService.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Activity; + +namespace Volo.Abp.Cli.Telemetry; + +public class NullTelemetryService : ITelemetryService +{ + public IAsyncDisposable TrackActivity(ActivityEvent activityData) + { + return NullAsyncDisposable.Instance; + } + public IAsyncDisposable TrackActivityAsync(string activityName, Action>? additionalProperties = null) + { + return NullAsyncDisposable.Instance; + } + + public Task AddActivityAsync(string activityName, Action>? additionalProperties = null) + { + return Task.CompletedTask; + } + + public Task AddErrorActivityAsync(Action> additionalProperties) + { + return Task.CompletedTask; + } + + public Task AddErrorActivityAsync(string errorMessage) + { + return Task.CompletedTask; + } + + public Task AddErrorForActivityAsync(string failingActivity, string errorMessage) + { + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli/Volo/Abp/Cli/Telemetry/TelemetryCliSessionProvider.cs b/framework/src/Volo.Abp.Cli/Volo/Abp/Cli/Telemetry/TelemetryCliSessionProvider.cs new file mode 100644 index 0000000000..17c340febd --- /dev/null +++ b/framework/src/Volo.Abp.Cli/Volo/Abp/Cli/Telemetry/TelemetryCliSessionProvider.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Internal.Telemetry.Activity; +using Volo.Abp.Internal.Telemetry.Activity.Contracts; +using Volo.Abp.Internal.Telemetry.Activity.Providers; +using Volo.Abp.Internal.Telemetry.Constants; +using Volo.Abp.Internal.Telemetry.Constants.Enums; + +namespace Volo.Abp.Cli.Telemetry; + +[ExposeServices(typeof(ITelemetryActivityEventEnricher))] +public class TelemetryCliSessionProvider : TelemetryActivityEventEnricher +{ + public TelemetryCliSessionProvider(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + + public override int ExecutionOrder { get; set; } = 10; + + protected override Task ExecuteAsync(ActivityContext context) + { + context.Current[ActivityPropertyNames.SessionType] = SessionType.AbpCli; + context.Current[ActivityPropertyNames.SessionId] = Guid.NewGuid(); + context.Current[ActivityPropertyNames.IsFirstSession] = !File.Exists(TelemetryPaths.ActivityStorage); + context.Current["OldCli"] = true; + + if(context.Current.TryGetValue>(ActivityPropertyNames.AdditionalProperties, out var additionalProperties)) + { + additionalProperties["OldCli"] = true; + } + else + { + context.Current[ActivityPropertyNames.AdditionalProperties] = new Dictionary + { + { "OldCli", true } + }; + } + + return Task.CompletedTask; + } +} \ No newline at end of file