Exemple #1
0
        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);
            }
        }
Exemple #3
0
        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));
 }
Exemple #10
0
 public CorrelationEnricher(IInstrumentationContext context)
 {
     _context = context ?? throw new ArgumentNullException(nameof(context));
 }
Exemple #11
0
        /// <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);
        }