Install vFunction Agent and OpenTelemetry on .NET Framework Application running on Containerized Windows-x64 via Dockerfile
Overview
Microsoft .NET Applications have a limitation that only one Agent can be hooked into the Application at a time. To work around this limitation, the Datadog Tracer can be used as the Base Agent. This Datadog Tracer includes a configuration file that allows you to define additional .NET Agents to run simultaneously on the Application without conflict.
At a high level, you’ll need to:
- Download and install the vFunction Monolithic .NET Agent
- Download and install the OpenTelemetry Agent
- Download and install the DataDog Multiplexer
- Create a script to add all required Environment Variables
- Modify the Dockerfile to bring all new components onto the Container
- Build and Deploy the new Container
.NET Framework Compatibility
vFunction supports C# .NET Framework version 4.8.x applications.
Installation Steps
Install the vFunction Monolithic Agent
- Ensure vFunction Monolithic Agent Prerequisites are met
- Download the vFunction Windows Controller Installation ZIP for the vFunction Monolithic Agent
- On the Build machine, create a vFunction directory where files can be stored
- Add the vFunction Windows Controller Installation ZIP to this directory
- Retrieve the vFunction UI’s Application UUIDs:
- Log into the vFunction Server’s UI in a browser
- In the top-left corner, click the dropdown and select the relevant Application
- In the top-center menu bar, click the “Learning” tab
- On the left-side, click the “Select Controllers” link
- On the left-side, click the “Install Controller” link
- In the dialog box, find the YAML-formatted text box that contains the following details. You’ll need these details at a later stage below:
controller:
name: {display name for this controller}
host: $your_VF_Server_address
org_id: 93af7f38-0000-0000-0000-bd9516798497
app_id: 9fb228fc-0000-0000-0000-db8e83427e14
client_id: caeadcd1-0000-0000-0000-9c9b37a9e119
client_secret: 68cb85eb-0000-0000-0000-fb9e7f1d9240
- Create an installation.yaml to be added to this vfunction directory on the Build machine
controller:
name: 'Windows-Container-Test'
host: 'https://vfunction.mycompany.com'
org_id: '45faddbf-1111-1111-1111-5c3846b4e751'
app_id: '2bef40e7-1111-1111-1111-b17975a62ca0'
client_id: '6f809ad3-1111-1111-1111-a86c17f9f9a9'
client_secret: 'b946d2d2-1111-1111-1111-463dc172b40a'
type: dotnet
instrconf_additions:
inclusions:
# - a.b.c.
exclusions:
# - a.b.c.
tags:
# - tag1
server_application:
# name:
# include_classes: com.
# allowed_users:
# new_user_default_password:
agent:
# optional versions: framework, dotnet
version: framework
# optional environments: iis, service, command
environment: service
# application_name:
# architecture: x86
# application_command:
### Set the log level for the agent (trace, debug, info, warning, error, critical). The default is debug.
# log_level: info
### Add process ID to log file name (true/false). Default is false ###
# add_pid_to_log_file: false
enable_rejit: true
Install the OpenTelemetry Agent
- Download the OpenTelemetry .NET Auto-instrumentation ZIP
- On the Build machine, create an OpenTelemetry directory where files can be stored
- Add the OpenTelemetry .NET Auto-instrumentation ZIP to this directory
- Gather the vFunction Server UI’s UUID for the OpenTelemetry Agent
- Log into the vFunction Server UI
- In the top-left corner, click the dropdown
- Click Add Application from the dropdown menu
- Type a name for the Application in the Application Name text field
- Toggle the slider to Distributed
- Click the blue Create button
- In the dialog box that launches, toggle the tabs to .NET
- In the text box with OTEL Environment Variables, find the OTEL_EXPORT_OTLP_ENDPOINT and OTEL_EXPORTER_OTLP_HEADER. These will be used at a later stage of the installation
Install the DataDog Multiplexer
- Download the DataDog Multiplexer
- Create a loader.conf configuration file for the DataDog Multiplexer
#Profiler
PROFILER;{918728DD-259F-4A6A-AC2B-B85E1B658318};win-x64;C:\otel\win-x64\OpenTelemetry.AutoInstrumentation.Native.dll
#Tracer
TRACER;{cd7d4b53-96c8-4552-9c11-6e41df8eab8a};win-x64;C:\vfunction\agent\vfagent.net.dll
- On the Build machine, create a DataDog directory where files can be stored
- Add the DataDog Multiplexer and the loader.conf to this directory
Create a PowerShell Script to add Environment Variables
- Create a vfunction-dockerfile-windows-service.ps1 to add to the vFunction directory on the Build machine. This script adds the vFunction Agent to the Datadog’s Loader.conf and it adds all Agent Environment Variables to the Registry for the relevant Windows Service
param (
[parameter(Mandatory=$true)] [string]$svc
)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -Force
############### VF Mono Values ###############
$HostUrl = ""
############### VF Dist Values ###############
$DistAppUUID = "X-VF-APP="
############### Paths ###############
$BASE_DIR = "C:"
$VF_BASE_DIR = "${BASE_DIR}\vfunction"
$DATADOG_BASE_DIR = "${BASE_DIR}\multiplexer"
$OTEL_BASE_DIR = "${BASE_DIR}\otel"
$VF_CONF_LOCATION = "${VF_BASE_DIR}\vfunction\config\agent\instances\${svc}\conf.json"
############### Additional values used in script #######################
$OTEL_ENDPOINT = "${HostUrl}/api/unauth/otlp"
$profiler = "${DATADOG_BASE_DIR}\Datadog.Trace.ClrProfiler.Native.dll"
# print all parameters
Write-Output "Running with parameters:"
if ($null -ne $svc -and $svc -ne ""){
Write-Output "instance: $svc"
}
function Set-WinSvcEnvVars {
$regPath = "HKLM:\SYSTEM\CurrentControlSet\Services\${svc}"
# Note that the values below will vary based on your installation location and Server URL
$newValues = @(
"VF_AGENT_CONF_LOCATION=${VF_CONF_LOCATION}",
"COMPlus_TailCallOpt=0",
"DOTNET_TailCallOpt=0",
"OTEL_DOTNET_AUTO_INSTALL_DIR=${OTEL_BASE_DIR}",
"DOTNET_ADDITIONAL_DEPS=${OTEL_BASE_DIR}\AdditionalDeps",
"DOTNET_SHARED_STORE=${OTEL_BASE_DIR}\store",
"DOTNET_STARTUP_HOOKS=${OTEL_BASE_DIR}\net\OpenTelemetry.AutoInstrumentation.StartupHook.dll",
"OTEL_DOTNET_AUTO_HOME=${OTEL_BASE_DIR}",
"OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_ENDPOINT}",
"OTEL_EXPORTER_OTLP_HEADERS=${DistAppUUID}",
"OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf",
"OTEL_TRACES_EXPORTER=otlp",
"OTEL_METRICS_EXPORTER=none",
"OTEL_LOGS_EXPORTER=none",
"COR_PROFILER_PATH_64=${profiler}",
"CORECLR_PROFILER_PATH_64=${profiler}",
"COR_PROFILER_PATH_32=${profiler}",
"CORECLR_PROFILER_PATH_32=${profiler}",
"COR_ENABLE_PROFILING=1",
"CORECLR_ENABLE_PROFILING=1",
"COR_PROFILER={846F5F1C-F9AE-4B07-969E-05C26BC060D8}",
"CORECLR_PROFILER={846F5F1C-F9AE-4B07-969E-05C26BC060D8}"
)
# Read existing values (default to empty array if none)
$item = Get-ItemProperty -Path $regPath -ErrorAction SilentlyContinue
if ($item -and $item.Environment) {
$existing = $item.Environment
}
else {
$existing = @()
}
# Merge, filtering out any duplicates
$merged = ($existing + $newValues) | Select-Object -Unique
New-ItemProperty `
-Path $regPath `
-Name Environment `
-Value $merged `
-PropertyType MultiString `
-Force
}
#################################################################
###################### Win SVC Configuration ####################
#################################################################
Set-WinSvcEnvVars
Modify the Dockerfile to add all new components
- Modify the Dockerfile used by the Application to add the vFunction Agent, OpenTelemetry Agent and DataDog Multiplexer
# escape=`
FROM mcr.microsoft.com/dotnet/framework/runtime:4.8
# Main Content of Dockerfile related to App
# Location where Datadog is added to the Container
RUN powershell -Command `
# Datadog APM
Start-Process msiexec.exe -Wait -ArgumentList '/I C:\datadog-dotnet-apm.msi /quiet'; `
net stop /y was;
# Copy vFunction (VF) files
COPY ["vfunction/vfunction-controller-windows*.zip", "C:/vfunction.zip"]
COPY ["vfunction/vfunction-dockerfile-windows-service.ps1", "C:/vfunction.ps1"]
COPY ["vfunction/installation.yaml", "C:/vfunction.yaml"]
# Set Windows Service Name for VF to hook
ENV SVC="CHANGE_ME"
# Expand VF dir
RUN powershell -ExecutionPolicy Bypass Expand-Archive -Path "C:/vfunction.zip" -DestinationPath "C:/";
# Create App-specific VF instance
RUN powershell -ExecutionPolicy Bypass -Command "& C:\vfunction\controller-installation\create-instance.ps1 `
-instance $env:SVC `
-agentMode true `
-type dotnet"
# Move App-specific configuration to created VF instance
RUN powershell -ExecutionPolicy Bypass Move-Item -Path "C:/vfunction.yaml" `
-Destination "C:/vfunction/config/installation/instances/$env:SVC/installation.yaml" -Force; `
icacls "C:\vfunction" /grant Everyone:F /T
# Set all VF Configuration Files
RUN powershell -ExecutionPolicy Bypass -Command "& C:\vfunction\controller-installation\install.ps1 `
-instance $env:SVC `
-noServices true `
-scriptMode true"
# Copy OpenTelemtry (OTEL) ZIP
COPY ["otel/opentelemetry-dotnet-instrumentation-windows.zip", "C:/otel.zip"]
# Create OTEL dir
RUN powershell -Command `
# Create Directory for DLL and Scripts
New-Item -ItemType directory -Path c:\otel;
# Expand OTEL ZIP
RUN powershell -ExecutionPolicy Bypass Expand-Archive -Path "C:/otel.zip" -DestinationPath "C:/otel";
# Create DataDog dir
RUN powershell -Command `
# Create Directory for DLL and Scripts
New-Item -ItemType directory -Path c:\multiplexer;
# Copy DataDog files
COPY ["multiplexer/Datadog.Trace.ClrProfiler.Native.dll", "C:/multiplexer/Datadog.Trace.ClrProfiler.Native.dll"]
COPY ["multiplexer/loader.conf", "C:/multiplexer/loader.conf"]
# Add all Agent Env Vars to Windows Service's Registry
RUN powershell -ExecutionPolicy Bypass -Command "& C:\vfunction.ps1 -svc $env:SVC"
# End of Dockerfile that starts the Container
Confirm Functionality
- Confirm the Docker Container builds as expected
- Confirm the Application functions as expected
- Confirm that the vFunction Distributed Agent is capturing informaton about the Application as expected
- Confirm that the vFunction Monolithic Agent is capturing data as expected by starting Learning and validating learning results