Skip to content

robertpi/sqreen-dotnet-windows

Repository files navigation

This the implementation of "How to add a header without changing the code base" home assignment.

Warning: this will clone and build the .NET Runtime, so requires 10 GB of disk-space, once built

Building

Currently there only build scripts for Windows. The C# parts will already work under Windows, Linux, macOS & FreeBSD, but the profiler will need build scripts for *nix OSs.

First ensure you have all the dependencies for Windows. To ensure all the correct packages from Visual Studio are installed make sure you import runtime/.vsconfig into the Visual Studio Installer, more details how to do this.

Once all the dependencies are installed first, from a normal Windows command prompt, execute:

runfirst-buildcoreclr.cmd

This will build the coreclr runtime. This will take some time, but you will only need to do this once. Secondly, execute:

build.cmd

To build and run the sample.

Testing

Hit http://localhost:5000/ in your favourite browser / tool.

browser screenshot

Architecture

To complete this project there are three steps:

  1. Build the coreclr source to obtain the necessary header and linker files to build the profiling API
  2. Create a profiler that will listen to the JIT profiling events and rewrite certain methods before the JIT
  3. Create a C# dll containing the methods to be injected, and also a test harness website to test the injection

Step One

Step one is fairly straight forward but can be time consuming to ensure all dependencies are setup correctly to complete the build.

Step Two

Step two is technically challenging, but fortunately there are some existing samples that are similar to what we want to achieve.

The code from this exercise is a modified version of ClrProfiler.Trace. This project demonstrates how to inject C# code into a dotnet core application being profiled, so the injected C# code can be responsible for collecting the profiling data.

This project relies on an outdated way for preforming cross platform complication, so I replaced it with the build system from doooot stacksampling which uses cmake like coreclr.

The important parts of the code are:

This file contains the constants that specific what method, from which type and assembly should be injected.

It also serves as the header file for clr_helpers.cpp, which contains some helpers to make working with CLR data structures easier.

This file contains the code that handles the call backs from the CLR. We are only interested in three callbacks:

  • ModuleLoadFinished - used to store info about the module / assembly being loaded, needed for IL rewriting
  • ModuleUnloadFinished - remove data about a module that has been unloaded
  • JITCompilationStarted - This tests if a method should be rewritten / have code injected and preforms the injection

There are two helper methods FunctionNeedsMiddlewareInject & MethodParamsNameIsMatch which use a heuristic to know if we should inject our code.

The environment variables need are:

  • CORECLR_ENABLE_PROFILING=1 - activates the profiler
  • CORECLR_PROFILER={88E5B029-D6B4-4709-B445-03E9BDAB2FA2} - sets COM ClassId of the profiler
  • CORECLR_PROFILER_PATH=%BatchDir%\..\..\profiler\bin\Debug\ClrProfiler.dll - tells the runtime where to load the profiler
  • CORECLR_PROFILER_HOME=%BatchDir%\bin\Debug\netcoreapp3.1\ - required by the profiler locate the code to be injected

Step Three

The code for step three is trivial. Adding a header to an aspnet core app is straight forward, this forms the body of the method that will be injected:

        app.Use(async (context, next) =>
        {
            context.Response.Headers.Add("X-Instrumented-By", "Sqreen");
            await next.Invoke();
        });

For the test website one of the templates available in Visual Studio can be used. Rather that starting the website directly a batch file is used to set the necessary environment variables required to load the profiler.

TODO

  • bash / *nix build scripts
  • improve profiler code:
    • separate injection code from callback code
    • improve heuristic for detecting function that requires injection
  • unit tests for the profiler code

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages