Skip to content

Commit

Permalink
feat: Add detailed assembly reporting to enable Vulnerability Managem…
Browse files Browse the repository at this point in the history
…ent support. (#1685)
  • Loading branch information
jaffinito authored Jun 3, 2023
1 parent e8bdc34 commit f249753
Show file tree
Hide file tree
Showing 21 changed files with 1,179 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2173,6 +2173,30 @@ public TimeSpan SqlTracesHarvestCycle
}
}

private TimeSpan? _updateLoadedModulesCycleOverride = null;
public TimeSpan UpdateLoadedModulesCycle
{
get
{
if (_updateLoadedModulesCycleOverride.HasValue)
{
return _updateLoadedModulesCycleOverride.Value;
}

if (_newRelicAppSettings.TryGetValue("OverrideUpdateLoadedModulesCycle", out var harvestCycle))
{
if (int.TryParse(harvestCycle, out var parsedHarvestCycle) && parsedHarvestCycle > 0)
{
Log.Info("Update loaded modules cycle overridden to " + parsedHarvestCycle + " seconds.");
_updateLoadedModulesCycleOverride = TimeSpan.FromSeconds(parsedHarvestCycle);
return _updateLoadedModulesCycleOverride.Value;
}
}

return DefaultHarvestCycle;
}
}

#endregion

#region Helpers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,9 @@ public ReportedConfiguration(IConfiguration configuration)
[JsonProperty("sql_traces.harvest_cycle")]
public TimeSpan SqlTracesHarvestCycle => _configuration.SqlTracesHarvestCycle;

[JsonProperty("update_loaded_modules.cycle")]
public TimeSpan UpdateLoadedModulesCycle => _configuration.UpdateLoadedModulesCycle;

public IReadOnlyDictionary<string, string> GetAppSettings()
{
return _configuration.GetAppSettings();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public interface IDataTransportService
DataTransportResponseStatus Send(IEnumerable<SqlTraceWireModel> sqlTraceWireModels);
DataTransportResponseStatus Send(IEnumerable<CustomEventWireModel> customEvents);
DataTransportResponseStatus Send(LogEventWireModelCollection loggingEvents);
DataTransportResponseStatus Send(LoadedModuleWireModelCollection loadedModules);
}

public class DataTransportService : ConfigurationBasedService, IDataTransportService
Expand Down Expand Up @@ -139,6 +140,16 @@ public DataTransportResponseStatus Send(IEnumerable<MetricWireModel> metrics)
return status;
}

public DataTransportResponseStatus Send(LoadedModuleWireModelCollection loadedModules)
{
if (loadedModules.LoadedModules.Count < 1)
{
return DataTransportResponseStatus.RequestSuccessful;
}

return TrySendDataRequest("update_loaded_modules", loadedModules);
}

#endregion Public API

#region Private helpers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ public static void RegisterServices(IContainer container)
}
container.Register<NewRelicCore.DistributedTracing.ITracePriorityManager, NewRelicCore.DistributedTracing.TracePriorityManager>();

container.Register<UpdatedLoadedModulesService, UpdatedLoadedModulesService>();

container.Build();
}

Expand Down Expand Up @@ -231,6 +233,7 @@ public static void StartServices(IContainer container)
container.Resolve<ThreadStatsSampler>().Start();
container.Resolve<ConfigurationTracker>();
container.Resolve<LiveInstrumentationServerConfigurationListener>();
container.Resolve<UpdatedLoadedModulesService>();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

using System;
using NewRelic.Agent.Core.WireModels;
using Newtonsoft.Json;

namespace NewRelic.Agent.Core.JsonConverters
{
public class LoadedModuleWireModelCollectionJsonConverter : JsonConverter<LoadedModuleWireModelCollection>
{
// The payload is labeled "Jars" since the collector method was originally meant for and used by Java.
private const string JarsName = "Jars";

public override LoadedModuleWireModelCollection ReadJson(JsonReader reader, Type objectType, LoadedModuleWireModelCollection existingValue, bool hasExistingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}

public override void WriteJson(JsonWriter jsonWriter, LoadedModuleWireModelCollection value, JsonSerializer serializer)
{
WriteJsonImpl(jsonWriter, value);
}

private static void WriteJsonImpl(JsonWriter jsonWriter, LoadedModuleWireModelCollection value)
{
jsonWriter.WriteValue(JarsName);

jsonWriter.WriteStartArray();

foreach (var loadedModule in value.LoadedModules)
{
// MODULE
jsonWriter.WriteStartArray();

jsonWriter.WriteValue(loadedModule.AssemblyName);
jsonWriter.WriteValue(loadedModule.Version ?? " ");

// DATA DICTIONARY
jsonWriter.WriteStartObject();
foreach (var item in loadedModule.Data)
{
jsonWriter.WritePropertyName(item.Key);
jsonWriter.WriteValue(item.Value.ToString());
}

jsonWriter.WriteEndObject();

jsonWriter.WriteEndArray();
}

jsonWriter.WriteEndArray();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

using System;
using System.Collections.Generic;
using System.Linq;
using NewRelic.Agent.Configuration;
using NewRelic.Agent.Core.DataTransport;
using NewRelic.Agent.Core.Time;
using NewRelic.Agent.Core.WireModels;

namespace NewRelic.Agent.Core.Utilities
{
public class UpdatedLoadedModulesService : DisposableService
{
private readonly IList<string> _loadedModulesSeen = new List<string>();
private readonly IScheduler _scheduler;
private readonly IDataTransportService _dataTransportService;
private readonly IConfigurationService _configurationService;
private IConfiguration _configuration => _configurationService?.Configuration;

public UpdatedLoadedModulesService(IScheduler scheduler, IDataTransportService dataTransportService, IConfigurationService configurationService)
{
_configurationService = configurationService;
_dataTransportService = dataTransportService;
_scheduler = scheduler;
_scheduler.ExecuteEvery(GetLoadedModules, _configuration.UpdateLoadedModulesCycle);
}

private void GetLoadedModules()
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(assembly => assembly != null)
.Where(assembly => !_loadedModulesSeen.Contains(assembly.GetName().Name))
#if NETFRAMEWORK
.Where(assembly => !(assembly is System.Reflection.Emit.AssemblyBuilder))
#endif
.ToList();

if (assemblies.Count < 1)
{
return;
}

var loadedModulesCollection = LoadedModuleWireModelCollection.Build(assemblies);

SendUpdatedLoadedModules(loadedModulesCollection);
}

private void SendUpdatedLoadedModules(LoadedModuleWireModelCollection loadedModulesCollection)
{
var responseStatus = _dataTransportService.Send(loadedModulesCollection);
if (responseStatus != DataTransportResponseStatus.RequestSuccessful)
{
// Try again next time
return;
}

foreach (var module in loadedModulesCollection.LoadedModules)
{
_loadedModulesSeen.Add(module.Data["namespace"].ToString());
}
}
}
}
23 changes: 23 additions & 0 deletions src/Agent/NewRelic/Agent/Core/WireModels/LoadedModuleWireModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

using System.Collections.Generic;

namespace NewRelic.Agent.Core.WireModels
{
public class LoadedModuleWireModel
{
public string AssemblyName { get; }

public string Version { get; }

public Dictionary<string, object> Data { get; }

public LoadedModuleWireModel(string assemblyName, string version)
{
AssemblyName = assemblyName;
Version = version;
Data = new Dictionary<string, object>();
}
}
}
Loading

0 comments on commit f249753

Please sign in to comment.