public InstrumentationResult Instrument(IInstrumentationContext context) { _logger.LogTrace("Hit services assembly location: {assemblyLocation}", hitServicesAssembly.Location); var result = new InstrumentationResult { SourcePath = context.Workdir.FullName, HitsPath = context.HitsPath }; var assemblyGroups = context.Assemblies .Where(ShouldInstrumentAssemblyFile) .GroupBy(FileUtils.GetFileHash) .ToArray(); foreach (var assemblyGroup in assemblyGroups) { VisitAssemblyGroup( context, result, assemblyGroup.ToArray()); } return(result); }
public InstrumentedAssembly InstrumentAssemblyFile( IInstrumentationContext context, IFileInfo assemblyFile) { var assemblyDirectory = assemblyFile.Directory; var resolver = ActivatorUtilities.CreateInstance <CustomAssemblyResolver>(_serviceProvider, assemblyDirectory); _logger.LogTrace("Assembly resolver search directories: {directories}", new object[] { resolver.GetSearchDirectories() }); try { using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyFile.FullName, new ReaderParameters { ReadSymbols = true, AssemblyResolver = resolver })) { return(InstrumentAssemblyDefinition(context, assemblyDefinition)); } } catch (BadImageFormatException) { _logger.LogInformation("Invalid assembly format"); return(null); } }
public void InstrumentType( IInstrumentationContext context, TypeDefinition typeDefinition, InstrumentedAssembly instrumentedAssembly) { foreach (var methodDefinition in typeDefinition.Methods) { if (!methodDefinition.HasBody || !methodDefinition.DebugInformation.HasSequencePoints) { continue; } var isTest = context.IsTest(methodDefinition); var isSource = context.IsSource(methodDefinition); if (!isSource && !isTest) { continue; } _methodInstrumenter.InstrumentMethod( context, isSource, methodDefinition, instrumentedAssembly); } foreach (var nestedType in typeDefinition.NestedTypes) { InstrumentType(context, nestedType, instrumentedAssembly); } }
public GlobalInterceptor( ILogger logger, IOptionsMonitor <LoggingOptions> options, IInstrumentationContext instrumentation) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _options = options.CurrentValue ?? new LoggingOptions(); _instrumentation = instrumentation ?? throw new ArgumentNullException(nameof(instrumentation)); }
internal static CallOptions WithTraceId(this CallOptions options, IInstrumentationContext context) { var headers = context.GetTracingHeaders(); foreach (var header in headers) { options.Headers.Add(header.Key, header.Value); } return(options); }
internal static CallOptions WithCorrelationHeader(this CallOptions options, IInstrumentationContext context) { options = options.Headers == null ? options.WithHeaders(new Metadata()) : options; (string name, string value) = context.GetCorrelationHeader(); options.Headers.Add(new Metadata.Entry(name, value)); return(options); }
private void InstrumentInstructions( IInstrumentationContext context, MethodDefinition methodDefinition, InstrumentedAssembly instrumentedAssembly, IList <(SequencePoint sequencePoint,
public void InstrumentMethod( IInstrumentationContext context, bool instrumentInstructions, MethodDefinition methodDefinition, InstrumentedAssembly instrumentedAssembly) { var originalMethod = methodDefinition.ResolveOriginalMethod(); var instrumentedMethod = instrumentedAssembly.GetOrAddMethod( originalMethod.DeclaringType.FullName, originalMethod.Name, originalMethod.FullName ); var methodContextClassReference = methodDefinition.Module.GetOrImportReference(methodScopeType); var enterMethodReference = methodDefinition.Module.GetOrImportReference(enterMethodInfo); var disposeMethodReference = methodDefinition.Module.GetOrImportReference(disposeMethodInfo); var sequencePointsInstructions = methodDefinition.MapSequencePointsToInstructions().ToArray(); var ilProcessor = methodDefinition.Body.GetILProcessor(); ilProcessor.Body.InitLocals = true; ilProcessor.Body.SimplifyMacros(); var methodContextVariable = new VariableDefinition(methodContextClassReference); ilProcessor.Body.Variables.Add(methodContextVariable); ilProcessor.RemoveTailInstructions(); var endFinally = ilProcessor.EncapsulateWithTryFinally(); ilProcessor.InsertBefore(endFinally, new[] { ilProcessor.Create(OpCodes.Ldloc, methodContextVariable), ilProcessor.Create(OpCodes.Callvirt, disposeMethodReference) }, true); ilProcessor.InsertBefore(ilProcessor.Body.Instructions[0], new[] { ilProcessor.Create(OpCodes.Ldstr, context.HitsPath), ilProcessor.Create(OpCodes.Ldstr, originalMethod.DeclaringType.Module.Assembly.Name.Name), ilProcessor.Create(OpCodes.Ldstr, originalMethod.DeclaringType.FullName), ilProcessor.Create(OpCodes.Ldstr, originalMethod.Name), ilProcessor.Create(OpCodes.Call, enterMethodReference), ilProcessor.Create(OpCodes.Stloc, methodContextVariable) }, true); if (instrumentInstructions && !methodDefinition.IsExcludedFromCodeCoverage()) { InstrumentInstructions( context, methodDefinition, instrumentedAssembly, sequencePointsInstructions, ilProcessor, methodContextVariable, instrumentedMethod); } ilProcessor.Body.OptimizeMacros(); }
public ClientFactory(IOptions <Collection <ChannelOptions> > channelOptions, IInstrumentationContext instrumentation) { _channelOptions = channelOptions.Value ?? new Collection <ChannelOptions>(); _instrumentation = instrumentation ?? throw new ArgumentNullException(nameof(instrumentation)); }
public CorrelationEnricher(IInstrumentationContext context) { _context = context ?? throw new ArgumentNullException(nameof(context)); }
/// <summary> /// An assembly group is a set of assemblies that are identical (the same file hash). This method makes sure we only instrument the first assembly in the group, to avoid unnecessary overhead. /// </summary> private void VisitAssemblyGroup( IInstrumentationContext context, InstrumentationResult result, IReadOnlyCollection <IFileInfo> assemblyFiles) { using (_logger.BeginScope("Checking assembly files {assemblies}", assemblyFiles.Select(f => f.FullName))) { var instrumentedAssembly = _assemblyInstrumenter.InstrumentAssemblyFile( context, assemblyFiles.First()); if (instrumentedAssembly == null) { return; } _logger.LogTrace("Temporary assembly file: {tempAssemblyFile}", instrumentedAssembly.TempAssemblyFile); _logger.LogTrace("Temporary PDB file: {tempPdbFile}", instrumentedAssembly.TempPdbFile); foreach (var assemblyFile in assemblyFiles) { _logger.LogDebug("Instrumenting assembly file {assemblyFile}", assemblyFile.FullName); if (_loadedAssemblyFiles.Contains(assemblyFile.FullName)) { _logger.LogInformation("Skipping loaded assembly {assemblyFile}", assemblyFile.FullName); continue; } var pdbFile = FileUtils.GetPdbFile(assemblyFile); var assemblyBackupFile = FileUtils.GetBackupFile(assemblyFile); var pdbBackupFile = FileUtils.GetBackupFile(pdbFile); _logger.LogTrace("PDB file: {pdbFileName}", pdbFile.FullName); _logger.LogTrace("Assembly backup file: {assemblyBackupFileName}", assemblyBackupFile.FullName); _logger.LogTrace("PDB backup file: {pdbBackupFileName}", pdbBackupFile.FullName); //Backup _fileSystem.File.Copy(assemblyFile.FullName, assemblyBackupFile.FullName, true); _fileSystem.File.Copy(pdbFile.FullName, pdbBackupFile.FullName, true); //Override assembly _fileSystem.File.Copy(instrumentedAssembly.TempAssemblyFile, assemblyFile.FullName, true); _fileSystem.File.Copy(instrumentedAssembly.TempPdbFile, pdbFile.FullName, true); //Copy instrumentation dependencies var assemblyDirectory = assemblyFile.Directory; _logger.LogTrace("Assembly directory: {assemblyDirectory}", assemblyDirectory.FullName); var hitServicesPath = Path.GetFileName(hitServicesAssembly.Location); var newHitServicesPath = Path.Combine(assemblyDirectory.FullName, hitServicesPath); _fileSystem.File.Copy(hitServicesAssembly.Location, newHitServicesPath, true); result.AddExtraAssembly(newHitServicesPath); instrumentedAssembly.AddLocation( assemblyFile.FullName, assemblyBackupFile.FullName, pdbFile.FullName, pdbBackupFile.FullName ); var hitServicesAssemblyVersion = FileVersionInfo.GetVersionInfo(hitServicesAssembly.Location); foreach (var depsJsonFile in assemblyDirectory.GetFiles("*.deps.json")) { _depsJsonUtils.PatchDepsJson(depsJsonFile, hitServicesAssemblyVersion.ProductVersion); } } result.AddInstrumentedAssembly(instrumentedAssembly); _fileSystem.File.Delete(instrumentedAssembly.TempAssemblyFile); _fileSystem.File.Delete(instrumentedAssembly.TempPdbFile); } }
public GlobalCallInvoker(Channel channel, IInstrumentationContext instrumentation) : base(channel) { _context = instrumentation ?? throw new ArgumentNullException(nameof(instrumentation)); }
private InstrumentedAssembly InstrumentAssemblyDefinition( IInstrumentationContext context, AssemblyDefinition assemblyDefinition) { if (assemblyDefinition.CustomAttributes.Any(a => a.AttributeType.Name == "InstrumentedAttribute")) { _logger.LogInformation("Already instrumented"); return(null); } var assemblyDocuments = assemblyDefinition.GetAllDocuments(); var changedDocuments = assemblyDocuments.Where(d => d.FileHasChanged()).ToArray(); if (changedDocuments.Any()) { if (_logger.IsEnabled(LogLevel.Debug)) { var changedFiles = changedDocuments.Select(d => d.Url).Distinct().ToArray(); _logger.LogDebug("Source files has changed: {changedFiles}", new object[] { changedFiles }); } else { _logger.LogInformation("Source files has changed"); } return(null); } var instrumentedAssembly = new InstrumentedAssembly(assemblyDefinition.Name.Name); var instrumentedAttributeReference = assemblyDefinition.MainModule.ImportReference(instrumentedAttributeConstructor); assemblyDefinition.CustomAttributes.Add(new CustomAttribute(instrumentedAttributeReference)); foreach (var typeDefinition in assemblyDefinition.MainModule.GetTypes()) { if (typeDefinition.FullName == "<Module>" || typeDefinition.FullName == "AutoGeneratedProgram" || typeDefinition.DeclaringType != null) { continue; } _typeInstrumenter.InstrumentType( context, typeDefinition, instrumentedAssembly); } if (!instrumentedAssembly.Methods.Any()) { _logger.LogInformation("Nothing to instrument"); return(null); } _logger.LogInformation("Assembly instrumented"); var miniCoverTempPath = GetMiniCoverTempPath(); var instrumentedAssemblyFile = _fileSystem.FileInfo.FromFileName(Path.Combine(miniCoverTempPath, $"{Guid.NewGuid()}.dll")); var instrumentedPdbFile = FileUtils.GetPdbFile(instrumentedAssemblyFile); assemblyDefinition.Write(instrumentedAssemblyFile.FullName, new WriterParameters { WriteSymbols = true }); instrumentedAssembly.TempAssemblyFile = instrumentedAssemblyFile.FullName; instrumentedAssembly.TempPdbFile = instrumentedPdbFile.FullName; return(instrumentedAssembly); }