opentelemetry-dotnet-instru.../tools/IntegrationsJsonGenerator/Program.cs

167 lines
6.1 KiB
C#

// <copyright file="Program.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.Encodings.Web;
using System.Text.Json;
const string instrumentMethodAttributeName = "OpenTelemetry.AutoInstrumentation.Instrumentations.InstrumentMethodAttribute";
var thisFilePath = GetSourceFilePathName();
var solutionFolder = Path.Combine(thisFilePath, "..", "..", "..");
var autoInstrumentationLibPath = Path.Combine(solutionFolder, "bin", "tracer-home", "netcoreapp3.1", "OpenTelemetry.AutoInstrumentation.dll");
var autoInstrumentationLib = Assembly.LoadFrom(autoInstrumentationLibPath);
var assemblyInstrumentMethodAttributes = autoInstrumentationLib.DefinedTypes
.Where(type => InheritsFrom(type, instrumentMethodAttributeName)).Select(x => x.FullName);
var integrations = new Dictionary<string, Integration>();
foreach (var typeInfo in autoInstrumentationLib.GetTypes())
{
foreach (var attribute in typeInfo.GetCustomAttributes()
.Where(a => assemblyInstrumentMethodAttributes.Contains(a.GetType().FullName)))
{
var integration = ConvertToIntegration(typeInfo.FullName, attribute);
if (!integrations.ContainsKey(integration.IntegrationName))
{
integrations.Add(
integration.IntegrationName,
new Integration
{
Name = integration.IntegrationName,
Type = integration.IntegartionType,
MethodReplacements = new List<MethodReplacement> { integration.MethodReplacement }
});
}
else
{
var integration2 = integrations[integration.IntegrationName];
integration2.MethodReplacements.Add(integration.MethodReplacement);
}
}
}
var productionIntegrations = integrations.Where(x => x.Key != "StrongNamedValidation").Select(x => x.Value)
.OrderBy(x => x.Name).ToArray();
var testIntegrations = integrations.Where(x => x.Key == "StrongNamedValidation").Select(x => x.Value)
.OrderBy(x => x.Name).ToArray();
UpdateIntegrationFile(Path.Combine(solutionFolder, "integrations.json"), productionIntegrations);
UpdateIntegrationFile(Path.Combine(solutionFolder, "test", "IntegrationTests", "StrongNamedTestsIntegrations.json"), testIntegrations);
bool InheritsFrom(Type type, string baseType)
{
while (true)
{
if (type.FullName == baseType)
{
return true;
}
if (type.BaseType is null)
{
return false;
}
type = type.BaseType;
}
}
(string IntegartionType, string IntegrationName, MethodReplacement MethodReplacement) ConvertToIntegration(string wrapperTypeName, Attribute attribute)
{
var integrationName = GetPropertyValue<string>("IntegrationName", attribute);
var integrationType = GetPropertyValue<object>("Type", attribute).ToString();
var methodReplacement = new MethodReplacement
{
Wrapper =
{
Type = wrapperTypeName
},
Target =
{
Assembly = GetPropertyValue<string>("AssemblyName", attribute), Type = GetPropertyValue<string>("TypeName", attribute),
Method = GetPropertyValue<string>("MethodName", attribute)
}
};
var returnTypeName = GetPropertyValue<string>("ReturnTypeName", attribute);
var parameterTypeNames = GetPropertyValue<string[]>("ParameterTypeNames", attribute);
methodReplacement.Target.SignatureTypes = new[] { returnTypeName }.Concat(parameterTypeNames).ToArray();
var minVersion = GetPropertyValue<string>("MinimumVersion", attribute).Split('.');
methodReplacement.Target.MinimumMajor = int.Parse(minVersion[0]);
if (minVersion.Length > 1 && minVersion[1] != "*")
{
methodReplacement.Target.MinimumMinor = int.Parse(minVersion[1]);
}
if (minVersion.Length > 2 && minVersion[2] != "*")
{
methodReplacement.Target.MinimumPath = int.Parse(minVersion[2]);
}
var maxVersion = GetPropertyValue<string>("MaximumVersion", attribute).Split('.');
methodReplacement.Target.MaximumMajor = int.Parse(maxVersion[0]);
if (maxVersion.Length > 1 && maxVersion[1] != "*")
{
methodReplacement.Target.MaximumMinor = int.Parse(maxVersion[1]);
}
if (maxVersion.Length > 2 && maxVersion[2] != "*")
{
methodReplacement.Target.MaximumPath = int.Parse(maxVersion[2]);
}
return (integrationType, integrationName, methodReplacement);
}
T GetPropertyValue<T>(string propertyName, Attribute attribute)
{
var type = attribute.GetType();
var getMethod = type.GetProperty(propertyName).GetGetMethod();
if (!getMethod.ReturnType.IsAssignableTo(typeof(T)))
{
throw new ArgumentException($"Property {propertyName} is not assignable to {typeof(T)}");
}
var value = getMethod.Invoke(attribute, Array.Empty<object>());
return (T)value;
}
void UpdateIntegrationFile(string filePath, Integration[] productionIntegrations1)
{
using var fileStream = new FileStream(filePath, FileMode.Truncate);
var jsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping };
JsonSerializer.Serialize(fileStream, productionIntegrations1, jsonSerializerOptions);
}
static string GetSourceFilePathName([CallerFilePath] string callerFilePath = null)
=> callerFilePath ?? string.Empty;