Skip to content

Commit

Permalink
Merge pull request #251 from siemens/feat/CAToolTelemetry_Application…
Browse files Browse the repository at this point in the history
…Insight

CA Tool telemetry
  • Loading branch information
MalavikaKrishnan100 authored Feb 24, 2025
2 parents 5a8ae2a + 4d1afe1 commit cd81e0c
Show file tree
Hide file tree
Showing 56 changed files with 614 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/ArtifactoryUploader/LCT.ArtifactoryUploader.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<ItemGroup>
<ProjectReference Include="..\LCT.Common\LCT.Common.csproj" />
<ProjectReference Include="..\LCT.Services\LCT.Services.csproj" />
<ProjectReference Include="..\LCT.Telemetry\LCT.Telemetry.csproj" />
</ItemGroup>

</Project>
7 changes: 7 additions & 0 deletions src/ArtifactoryUploader/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using log4net;
using log4net.Core;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
Expand Down Expand Up @@ -91,6 +92,12 @@ static async Task Main(string[] args)
JfrogRepoUpdater.jFrogService = GetJfrogService(appSettings);
await PackageUploader.UploadPackageToArtifactory(appSettings);

// Initialize telemetry with CATool version and instrumentation key only if Telemetry is enabled in appsettings
if (appSettings.Telemetry.Enable == true)
{
TelemetryHelper telemetryHelper = new TelemetryHelper(appSettings);
telemetryHelper.StartTelemetry(caToolInformation.CatoolVersion, PackageUploader.uploaderKpiData, TelemetryConstant.ArtifactoryUploaderKpiData);
}
Logger.Logger.Log(null, Level.Notice, $"End of Artifactory Uploader execution : {DateTime.Now}\n", null);
// publish logs and BOM file to pipeline artifact

Expand Down
6 changes: 6 additions & 0 deletions src/LCT.Common/CommonAppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public string ProjectType
}
}
public bool MultipleProjectType { get; set; } = false;
public Telemetry Telemetry { get; set; }
public SW360 SW360 { get; set; }
public Directory Directory { get; set; }
public Jfrog Jfrog { get; set; }
Expand Down Expand Up @@ -95,6 +96,11 @@ public string LogFolderPath
}
}
}
public class Telemetry
{
public bool Enable { get; set; } = true;
public string ApplicationInsightInstrumentKey { get; set; }
}
public class SW360
{
private string m_URL;
Expand Down
28 changes: 28 additions & 0 deletions src/LCT.Common/Constants/TelemetryConstant.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// --------------------------------------------------------------------------------------------------------------------
// SPDX-FileCopyrightText: 2025 Siemens AG
//
// SPDX-License-Identifier: MIT
// --------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LCT.Common.Constants
{
[ExcludeFromCodeCoverage]
public class TelemetryConstant
{
public const string ToolName = "CATool";
public const string PackageIdentifier = "PackageIdentifierExecution";
public const string PackageCreator = "PackageCreatorExecution";
public const string ArtifactoryUploader = "ArtifactoryUploaderExecution";
public const string IdentifierKpiData = "IdentifierKpiDataTelemetry";
public const string CreatorKpiData = "CreatorKpiDataTelemetry";
public const string ArtifactoryUploaderKpiData = "UploaderKpiDataTelemetry";
public const string Type = "ApplicationInsights";
public const string StartLogMessage = "Telemetry tracking is now active for this execution. To turn off telemetry, use the command-line option --Telemetry:Enable false or adjust the settings in your appsettings file.";
}
}
1 change: 1 addition & 0 deletions src/LCT.Common/LCT.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

<ItemGroup>
<ProjectReference Include="..\LCT.CycloneDxProcessor\LCT.CycloneDxProcessor.csproj" />
<ProjectReference Include="..\LCT.Telemetry\LCT.Telemetry.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
100 changes: 100 additions & 0 deletions src/LCT.Common/TelemetryHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// --------------------------------------------------------------------------------------------------------------------
// SPDX-FileCopyrightText: 2025 Siemens AG
//
// SPDX-License-Identifier: MIT
// --------------------------------------------------------------------------------------------------------------------
using LCT.Common.Constants;
using LCT.Common.Interface;
using LCT.Telemetry;
using log4net;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;

namespace LCT.Common
{
public class TelemetryHelper
{
private readonly ILog Logger;
LCT.Telemetry.Telemetry telemetry_;
EnvironmentHelper environmentHelper;
CommonAppSettings appSettings_;

public TelemetryHelper(CommonAppSettings appSettings)
{
environmentHelper = new EnvironmentHelper();
Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
appSettings_ = appSettings ?? new CommonAppSettings();

telemetry_ = new LCT.Telemetry.Telemetry(TelemetryConstant.Type, new Dictionary<string, string>
{
{ "InstrumentationKey", appSettings.Telemetry.ApplicationInsightInstrumentKey }
});
}

public void StartTelemetry<T>(string catoolVersion, T kpiData,string telemetryFor)
{
// Initialize telemetry with CATool version and instrumentation key only if Telemetry is enabled in appsettings
Logger.Warn(TelemetryConstant.StartLogMessage);
try
{
InitializeAndTrackEvent(TelemetryConstant.ToolName, catoolVersion, telemetryFor
, appSettings_);
TrackKpiDataTelemetry(telemetryFor, kpiData);
}
catch (Exception ex)
{
Logger.Error($"An error occurred: {ex.Message}");
TrackException(ex);
environmentHelper.CallEnvironmentExit(-1);
}
finally
{
telemetry_.Flush(); // Ensure telemetry is sent before application exits
}
}

private void InitializeAndTrackEvent(string toolName, string toolVersion, string eventName,
CommonAppSettings appSettings)
{
telemetry_.Initialize(toolName, toolVersion);

telemetry_.TrackCustomEvent(eventName, new Dictionary<string, string>
{
{ "CA Tool Version", toolVersion },
{ "SW360 Project Name", appSettings.SW360.ProjectName },
{ "SW360 Project ID", appSettings.SW360.ProjectID },
{ "Project Type", appSettings.ProjectType },
{ "Hashed User ID", HashUtility.GetHashString(Environment.UserName) },
{ "Start Time", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture) }
});
}
private void TrackKpiDataTelemetry<T>(string eventName, T kpiData)
{
var properties = typeof(T).GetProperties();
var telemetryData = properties.ToDictionary(
prop => prop.GetCustomAttribute<DisplayNameAttribute>()?.DisplayName ?? prop.Name,
prop => prop.GetValue(kpiData)?.ToString()
);

telemetryData["Hashed User ID"] = HashUtility.GetHashString(Environment.UserName);
telemetryData["Time stamp"] = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);

telemetry_.TrackCustomEvent(eventName, telemetryData);
}

private void TrackException(Exception ex)
{
var exceptionData = new Dictionary<string, string>
{
{ "Error Time", DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture) },
{ "Stack Trace", ex.StackTrace }
};

telemetry_.TrackException(ex, exceptionData);
}
}
}
4 changes: 4 additions & 0 deletions src/LCT.Common/appSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
"TimeOut": 400,
"ProjectType": "<Insert ProjectType>",
"MultipleProjectType": false,
"Telemetry": {
"Enable": true,
"ApplicationInsightInstrumentKey": "" //From Application Insight to enable Telemetry
},
"SW360": {
"URL": "<Insert SW360URL>",
"ProjectName": "<Insert SW360 Project Name>",
Expand Down
1 change: 1 addition & 0 deletions src/LCT.PackageIdentifier/LCT.PackageIdentifier.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<ProjectReference Include="..\LCT.Common\LCT.Common.csproj" />
<ProjectReference Include="..\LCT.Facade\LCT.Facade.csproj" />
<ProjectReference Include="..\LCT.Services\LCT.Services.csproj" />
<ProjectReference Include="..\LCT.Telemetry\LCT.Telemetry.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
7 changes: 6 additions & 1 deletion src/LCT.PackageIdentifier/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,13 @@ static async Task Main(string[] args)
await bomCreator.GenerateBom(appSettings, new BomHelper(), new FileOperations(), projectReleases,
caToolInformation);
}
Logger.Logger.Log(null, Level.Notice, $"End of Package Identifier execution : {DateTime.Now}\n", null);

if (appSettings.Telemetry.Enable == true)
{
TelemetryHelper telemetryHelper = new TelemetryHelper(appSettings);
telemetryHelper.StartTelemetry(caToolInformation.CatoolVersion, BomCreator.bomKpiData, TelemetryConstant.IdentifierKpiData);
}
Logger.Logger.Log(null, Level.Notice, $"End of Package Identifier execution : {DateTime.Now}\n", null);
// publish logs and bom file to pipeline artifact
PipelineArtifactUploader.UploadArtifacts();

Expand Down
4 changes: 3 additions & 1 deletion src/LCT.SW360PackageCreator/ComponentCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ namespace LCT.SW360PackageCreator
public class ComponentCreator : IComponentCreator
{
static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

public static CreatorKpiData kpiData = new();
public List<ComparisonBomData> UpdatedCompareBomData { get; set; } = new List<ComparisonBomData>();
public List<ReleaseLinked> ReleasesFoundInCbom { get; set; } = new List<ReleaseLinked>();
public List<Components> ComponentsNotLinked { get; set; } = new List<Components>();
Expand Down Expand Up @@ -255,7 +257,7 @@ public async Task CreateComponentInSw360(CommonAppSettings appSettings,
FileConstant.ComponentsWithoutSrcFileName, appSettings.SW360.ProjectName);

// write Kpi Data
CreatorKpiData kpiData = creatorHelper.GetCreatorKpiData(UpdatedCompareBomData);
kpiData =creatorHelper.GetCreatorKpiData (UpdatedCompareBomData);
fileOperations.WriteContentToFile(kpiData, bomGenerationPath,
FileConstant.CreatorKpiDataFileName, appSettings.SW360.ProjectName);

Expand Down
2 changes: 1 addition & 1 deletion src/LCT.SW360PackageCreator/CreatorHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ public CreatorKpiData GetCreatorKpiData(List<ComparisonBomData> updatedCompareBo
Program.CreatorStopWatch.Stop();
creatorKpiData.TimeTakenByComponentCreator =
TimeSpan.FromMilliseconds(Program.CreatorStopWatch.ElapsedMilliseconds).TotalSeconds;

return creatorKpiData;
}

Expand Down
1 change: 1 addition & 0 deletions src/LCT.SW360PackageCreator/LCT.SW360PackageCreator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<ProjectReference Include="..\LCT.Common\LCT.Common.csproj" />
<ProjectReference Include="..\LCT.Facade\LCT.Facade.csproj" />
<ProjectReference Include="..\LCT.Services\LCT.Services.csproj" />
<ProjectReference Include="..\LCT.Telemetry\LCT.Telemetry.csproj" />
</ItemGroup>

<ProjectExtensions><VisualStudio><UserProperties /></VisualStudio></ProjectExtensions>
Expand Down
7 changes: 6 additions & 1 deletion src/LCT.SW360PackageCreator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,12 @@ static async Task Main(string[] args)
await CreatorValidator.TriggerFossologyValidation(appSettings, sW360ApicommunicationFacade);
}
await InitiatePackageCreatorProcess(appSettings, sw360ProjectService, sW360ApicommunicationFacade);

// Initialize telemetry with CATool version and instrumentation key only if Telemetry is enabled in appsettings
if (appSettings.Telemetry.Enable == true)
{
TelemetryHelper telemetryHelper = new TelemetryHelper(appSettings);
telemetryHelper.StartTelemetry(caToolInformation.CatoolVersion, ComponentCreator.kpiData,TelemetryConstant.CreatorKpiData);
}
Logger.Logger.Log(null, Level.Notice, $"End of Package Creator execution: {DateTime.Now}\n", null);

// publish logs and bom file to pipeline artifact
Expand Down
58 changes: 58 additions & 0 deletions src/LCT.Telemetry/ApplicationInsightsTelemetryProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// --------------------------------------------------------------------------------------------------------------------
// SPDX-FileCopyrightText: 2025 Siemens AG
//
// SPDX-License-Identifier: MIT
// --------------------------------------------------------------------------------------------------------------------
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.ApplicationInsights.Extensibility;

namespace LCT.Telemetry
{
public class ApplicationInsightsTelemetryProvider : ITelemetryProvider
{
private readonly TelemetryClient _telemetryClient;

public ApplicationInsightsTelemetryProvider(Dictionary<string, string> configuration)
{
var instrumentationKey = configuration.GetValueOrDefault("InstrumentationKey")
?? Environment.GetEnvironmentVariable("TelemetryInstrumentationKey");

if (string.IsNullOrEmpty(instrumentationKey))
{
throw new InvalidOperationException("Application Insights Instrumentation Key is missing or invalid.");
}

var aiConfig = TelemetryConfiguration.CreateDefault();
aiConfig.InstrumentationKey = instrumentationKey;

_telemetryClient = new TelemetryClient(aiConfig);
}

public void TrackEvent(string eventName, Dictionary<string, string> properties = null)
{
_telemetryClient.TrackEvent(eventName, properties);
}

public void TrackException(Exception ex, Dictionary<string, string> properties = null)
{
var exceptionTelemetry = new ExceptionTelemetry(ex);

if (properties != null)
{
foreach (var property in properties)
{
exceptionTelemetry.Properties[property.Key] = property.Value;
}
}

_telemetryClient.TrackException(exceptionTelemetry);
}

public void Flush()
{
_telemetryClient.Flush();
Thread.Sleep(1000); // Allow some time for telemetry to be sent
}
}
}
27 changes: 27 additions & 0 deletions src/LCT.Telemetry/HashUtility.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// --------------------------------------------------------------------------------------------------------------------
// SPDX-FileCopyrightText: 2025 Siemens AG
//
// SPDX-License-Identifier: MIT
// --------------------------------------------------------------------------------------------------------------------
using System.Security.Cryptography;
using System.Text;

namespace LCT.Telemetry
{
public static class HashUtility
{
public static string GetHashString(string input)
{
if (string.IsNullOrEmpty(input))
{
return string.Empty;
}

using (var hashAlgorithm = SHA256.Create())
{
byte[] hashBytes = hashAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(input));
return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
}
}
}
}
14 changes: 14 additions & 0 deletions src/LCT.Telemetry/ITelemetryProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// --------------------------------------------------------------------------------------------------------------------
// SPDX-FileCopyrightText: 2025 Siemens AG
//
// SPDX-License-Identifier: MIT
// --------------------------------------------------------------------------------------------------------------------
namespace LCT.Telemetry
{
public interface ITelemetryProvider
{
void TrackEvent(string eventName, Dictionary<string, string> properties = null);
void TrackException(Exception ex, Dictionary<string, string> properties = null);
void Flush();
}
}
22 changes: 22 additions & 0 deletions src/LCT.Telemetry/LCT.Telemetry.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Version>7.0.2</Version>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<OutputPath>..\..\out</OutputPath>
</PropertyGroup>

<PropertyGroup>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.22.0" />
</ItemGroup>

</Project>
Loading

0 comments on commit cd81e0c

Please sign in to comment.