# Configuring the Profiler-Initiated Collector

#### Why use the Profiler-Initiated Collector (PIC) approach?

The **PIC approach** simplifies .NET application instrumentation by leveraging built-in .NET / .NET Core profiling. It lets the profiler start the collector automatically as a detached process, with settings provided via **environment variables** or a **configuration file**, and stops the collector when the profiled process ends.

In some environments, there is no straightforward place to start the Coverage Collector explicitly:

* **Docker** – modifying the entry point or command script can be complex.
* **Azure / Azure DevOps** – no way to start the collector before IIS or override the test runner.
* **PCF** – background tasks complicate executing commands to stop the collector (aka BGTL).

To enable this feature, set the environment variable `SL_PROFILER_INITIALIZECOLLECTOR=1` to instruct the SeaLights Profiler to initialize its collector.

**Best Practice:** For containerized environments where you prefer not to modify the image, mount a folder containing the SeaLights Agent and point the profiler to it via the mounted path.

## Agent Setup <a href="#agent-setup" id="agent-setup"></a>

To instruct the profiler to start the collector, the target process should have a set of environmental variables:

{% tabs %}
{% tab title="Powershell" %}
{% code overflow="wrap" lineNumbers="true" %}

```powershell
# .Net Legacy
[Environment]::SetEnvironmentVariable("COR_ENABLE_PROFILING", "1", "Machine")
[Environment]::SetEnvironmentVariable("COR_PROFILER", "{01CA2C22-DC03-4FF5-8350-59E32A3536BA}", "Machine")
[Environment]::SetEnvironmentVariable("COR_PROFILER_PATH_32", "path\to\SL.DotNet.ProfilerLib.Windows_x86.dll", "Machine")
[Environment]::SetEnvironmentVariable("COR_PROFILER_PATH_64", "path\to\SL.DotNet.ProfilerLib.Windows_x64.dll", "Machine")
# .NetCore
[Environment]::SetEnvironmentVariable("CORECLR_ENABLE_PROFILING", "1", "Machine")
[Environment]::SetEnvironmentVariable("CORECLR_PROFILER", "{01CA2C22-DC03-4FF5-8350-59E32A3536BA}", "Machine")
[Environment]::SetEnvironmentVariable("CORECLR_PROFILER_PATH_32", "path\to\SL.DotNet.ProfilerLib.Windows_x86.dll", "Machine")
[Environment]::SetEnvironmentVariable("CORECLR_PROFILER_PATH_64", "path\to\SL.DotNet.ProfilerLib.Windows_x64.dll", "Machine")

[Environment]::SetEnvironmentVariable("SL_PROFILER_INITIALIZECOLLECTOR", "1", "Machine")
[Environment]::SetEnvironmentVariable('SL_BUILDSESSIONID', "$SL_BSID", "Machine")
#[Environment]::SetEnvironmentVariable('SL_BUILDSESSIONIDFILE', "path\to\buildSessionId.txt", "Machine")
[Environment]::SetEnvironmentVariable('SL_TOKENFILE', "path\to\sltoken.txt", "Machine")
[Environment]::SetEnvironmentVariable('SL_LABID', "$LAB_ID", "Machine")
#[Environment]::SetEnvironmentVariable("SL_PROFILER_INCLUDEPROCESSFILTER", "*include*,*what*,*is*,*ne?ded*", "Machine")

#Optional parameters
#[Environment]::SetEnvironmentVariable("SL_PROFILER_EXCLUDEPROCESSFILTER", "*exclude*,*unnee?ed", "Machine")
#[Environment]::SetEnvironmentVariable("SL_COVERAGECOLLECTOR_STARTUPINACTIVITYTIMEOUTSEC", "10", "Machine")
#[Environment]::SetEnvironmentVariable("SL_COVERAGECOLLECTOR_IDLETIMEOUTSEC", "0", "Machine")
```

{% endcode %}
{% endtab %}

{% tab title="Linux" %}
{% code overflow="wrap" lineNumbers="true" %}

```sh
export CORECLR_ENABLE_PROFILING=1
export CORECLR_PROFILER="{3B1DAA64-89D4-4999-ABF4-6A979B650B7D}"
export CORECLR_PROFILER_PATH_32="path\to\libSL.DotNet.ProfilerLib.Linux.so"
export CORECLR_PROFILER_PATH_64="path\to\libSL.DotNet.ProfilerLib.Linux.so"

export SL_PROFILER_INITIALIZECOLLECTOR=1
export SL_BUILDSESSIONID="$SL_BSID"
#export SL_BUILDSESSIONIDFILE="path\to\buildSessionId.txt"
export SL_TOKENFILE="path\to\sltoken.txt"
export SL_LABID="$LAB_ID"
#export SL_PROFILER_INCLUDEPROCESSFILTER="*include*,*what*,*is*,*ne?ded*"

#Optional parameters
#export SL_PROFILER_EXCLUDEPROCESSFILTER="*exclude*,*unnee?ed"
#export SL_COVERAGECOLLECTOR_STARTUPINACTIVITYTIMEOUTSEC=10
#export SL_COVERAGECOLLECTOR_IDLETIMEOUTSEC=0
```

{% endcode %}
{% endtab %}
{% endtabs %}

If the process starts successfully, the profiler starts a connection to the collector using the same key. If the profiled process has child processes, they will reuse the same collector in most cases.

{% hint style="warning" %}
Ensure the variables specifying the profiler path are correct, given where you installed the agent binaries (for example: `CORECLR_PROFILER_PATH_32=/usr/local/lib/libSL.DotNet.ProfilerLib.Linux.so`)
{% endhint %}

{% hint style="success" %}
When you successfully complete this step, you will see new entries appear in the *Cockpit > Live Agents Monitor*: the testListener and an entity called `Profiler` with the version details of your application.
{% endhint %}

## Common Options <a href="#logging-optional" id="logging-optional"></a>

### Logging (Optional) <a href="#logging-optional" id="logging-optional"></a>

Logging helps diagnose issues related to the profiler or collector startup, configuration, and connectivity. You can enable and fine-tune logging by setting the following environment variables:

{% tabs %}
{% tab title="Powershell" %}
{% code overflow="wrap" lineNumbers="true" %}

```powershell
[Environment]::SetEnvironmentVariable("SL_LOGGING_ENABLED", "true", "Machine")
[Environment]::SetEnvironmentVariable("SL_LOGLEVEL", "Debug", "Machine")
[Environment]::SetEnvironmentVariable("SL_LOGGING_TOFILE", "true", "Machine")
[Environment]::SetEnvironmentVariable("SL_LOGDIR", "path/to/logs/", "Machine")
[Environment]::SetEnvironmentVariable("SL_LOGGING_FILENAME", "path/to/logs/pic.log", "Machine")
```

{% endcode %}
{% endtab %}

{% tab title="Linux" %}
{% code overflow="wrap" lineNumbers="true" %}

```sh
export SL_LOGGING_ENABLED="true"
export SL_LOGLEVEL="Debug"
export SL_LOGGING_TOFILE="true"
export SL_LOGDIR="path/to/logs/"
export SL_LOGGING_FILENAME="path/to/logs/pic.log"
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
For advanced logging capabilities — such as controlling verbosity levels, enabling performance monitoring, or limiting logs to the Collector only — refer to the [Agent Logging Configuration](https://docs.sealights.io/knowledgebase/setup-and-configuration/sealights-agents-and-plugins/command-reference#background-listener) section of the documentation.
{% endhint %}

## Specific configurations <a href="#logging-optional" id="logging-optional"></a>

### IIS/Windows

If your application is deployed on IIS, follow the steps below:

* Don’t publish the application in **single-file** or **portable** mode.

{% stepper %}
{% step %}

#### Define the Environment Variables&#x20;

Define all necessary environment variables using **absolute paths**:

```
COR_ENABLE_PROFILING=1
COR_PROFILER={01CA2C22-DC03-4FF5-8350-59E32A3536BA}
COR_PROFILER_PATH=C:\AbsolutePathToAgentFolder\SL.DotNet.ProfilerLib.Windows_x64.dll
COR_PROFILER_PATH_32=C:\AbsolutePathToAgentFolder\SL.DotNet.ProfilerLib.Windows_x86.dll
COR_PROFILER_PATH_64=C:\AbsolutePathToAgentFolder\SL.DotNet.ProfilerLib.Windows_x64.dll
CORECLR_ENABLE_PROFILING=1
CORECLR_PROFILER={01CA2C22-DC03-4FF5-8350-59E32A3536BA}
CORECLR_PROFILER_PATH_32=C:\AbsolutePathToAgentFolder\SL.DotNet.ProfilerLib.Windows_x86.dll
CORECLR_PROFILER_PATH_64=C:\AbsolutePathToAgentFolder\SL.DotNet.ProfilerLib.Windows_x64.dll
SL_PROFILER_INITIALIZECOLLECTOR=1
SL_TOKENFILE=C:\AbsolutePathToAgentFolder\sltoken.txt
SL_LABID=integ_main_TestAppWeatherApi
SL_BUILDSESSIONIDFILE=C:\AbsolutePathToFolder\buildSessionId.txt
SL_LOGLEVEL=Debug
SL_LOGGING_TOFILE=true
SL_LOGDIR=C:\AbsolutePathToLogsFolder\
```

{% hint style="info" %}

#### **Optimizing Collector Usage Across Multiple IIS Sites**

If your IIS server hosts multiple sites on the same machine, each application pool will, by default, start its own profiler and Coverage Collector. This can increase resource usage.

To reduce the number of active collectors, configure all profilers to connect to a **single shared collector** by adding the following environment variables to your existing configuration:

```
SL_AGENT_PORT=31031
SL_COVERAGECOLLECTOR_STARTUPINACTIVITYTIMEOUTSEC=5
```

These settings ensure that all profilers share a single collector instance bound to the specified port, while unused collectors terminate quickly after a short inactivity period.  This approach reduces system overhead and optimizes resource usage.
{% endhint %}
{% endstep %}

{% step %}

#### Set the Variables in the Windows Registry

You can update the IIS environment variables in the Windows Registry using **either a manual approach or PowerShell commands**; both methods achieve the same result.

{% tabs %}
{% tab title="Manually" %}
Set the environment variables for the IIS services in the Windows Registry:

* Open the registry keys `Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WAS` **and** `Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W3SVC`
* Add a new **Multi-String** value named **Environment**

<figure><img src="https://docs.sealights.io/knowledgebase/~gitbook/image?url=https%3A%2F%2F4057366433-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FAjqTCMRYvHhDgsdPLUnc%252Fuploads%252FXcrIZoDp76JyKLUOe9nW%252Fimage-20240425-142701.png%3Falt%3Dmedia%26token%3D6422eb15-b293-45e5-8fee-16dc3e7a470e&#x26;width=768&#x26;dpr=4&#x26;quality=100&#x26;sign=2f716bb8&#x26;sv=2" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
*To remove the environment variables manually, simply delete the **Environment** value from both registry keys.*
{% endhint %}
{% endtab %}

{% tab title=" Powershell Commands" %}
You can store your environment variable configuration in a text file (for example, `SL-IIS-Envvars.txt`) and use the following command to add it to the Registry:

{% code overflow="wrap" %}

```powershell
"WAS","W3SVC" | ForEach-Object { Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\$_" -Name "Environment" -Value (Get-Content 'C:\AbsolutePathToFolder\SL-IIS-Envvars.txt') -Type MultiString }
```

{% endcode %}

{% hint style="warning" %}
*To remove the configuration, run the following command:*

{% code overflow="wrap" %}

```powershell
"WAS","W3SVC" | ForEach-Object { Remove-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\$_" -Name "Environment" }
```

{% endcode %}
{% endhint %}
{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

#### Restart the IIS Server to apply the changes&#x20;

* Restart the IIS Server using `iisreset /restart`
* Access your web application once to **wake it up** and verify that profiling starts correctly.
  {% endstep %}
  {% endstepper %}

{% hint style="success" %}
When this step is complete, new entries will appear in **Cockpit > Live Agents Monitor**: the `testListener` and an entity named `Profiler`, showing the version details of your application and the IIS AppPool it is attached to in the **Tag** column
{% endhint %}

### Kubernetes / Containerized Deployment

If you can’t modify the image:

* Mount a shared volume with the agent binaries.
* Set env vars in the app container (see below).
* Optionally use an **initContainer** to fetch the agent dynamically.

{% code overflow="wrap" lineNumbers="true" %}

```yaml
spec:
  initContainers:
  - name: sealights-dotnet-agent
    image: ubuntu:latest
    imagePullPolicy: IfNotPresent
    command: ["/bin/sh", "-c"]
    args:
      - |
      	wget -nv -O sealights-dotnet-agent-linux.tar.gz https://agents.sealights.co/dotnetcore/latest/sealights-dotnet-agent-linux-self-contained.tar.gz
        tar -xzf ./sealights-dotnet-agent-linux.tar.gz --directory /sealights
        echo "[Sealights] .NetCore Agent version is: $(cat /sealights/version.txt)"
    volumeMounts:
      - mountPath: /sealights
        name: sealights-dotnet-agent-file
  containers:
  - name: your-app-service-container
    # other container configurations
	# [...]
    env:
      # Profiler - Generic vars
      - name: SL_TOKEN
          secretKeyRef:
          name: sealights
          key: SEALIGHTS_AGENT_TOKEN
      - name: CORECLR_ENABLE_PROFILING
	value: "1"
      - name: CORECLR_PROFILER
	value: "{3B1DAA64-89D4-4999-ABF4-6A979B650B7D}"
      - name: CORECLR_PROFILER_PATH_32
	value: /sealights/libSL.DotNet.ProfilerLib.Linux.so
      - name: CORECLR_PROFILER_PATH_64
	value: /sealights/libSL.DotNet.ProfilerLib.Linux.so
      - name: SL_PROFILER_INITIALIZECOLLECTOR
	value: 1
      - name: SL_PROFILER_BLOCKING_CONNECTION_STARTUP
	value: "ASYNC"
      ### SL Profiler - Logging 
      - name: SL_LOGLEVEL
        value: "Debug"
      - name: SL_LOGGING_TOFILE
        value: "true"
      - name: SL_LOGDIR
        value: /sealights/logs/
      ### SL Profiler - Env Specific vars
      - name: SL_BUILDSESSIONIDFILE
        value: "path\to\buildSessionId.txt"
      - name: SL_LABID
        value: "integ_main_mysampleapplication"
    volumeMounts:
      - mountPath: /sealights
        name: sealights-dotnet-agent-file
  volumes:
    - name: sealights-dotnet-agent-file
      emptyDir: {}
```

{% endcode %}
