# Running Backend Server Using SeaLights Agent

In order to capture code coverage on your backend server, you need to run it using our Python test listener agent. Below you’ll find several options depending on your server type.

{% hint style="warning" %}
The below commands assume the **token** and **session id** are located in the working directory. If not, you can provide the file locations using the **sl.tokenFile** and **sl.buildSessionIdFile** environment variables
{% endhint %}

## uWSGI <a href="#uwsgi" id="uwsgi"></a>

When working with uWSGI, you need to run it with the following flags either in the command line or in the uwsgi configuration file: `--enable-threads  --single-interpreter --lazy-apps --import python_agent.init`

If you need to pass the parameters via the CLI, the command line will be similar to this

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

```javascript
uwsgi ... --enable-threads  --single-interpreter --import python_agent.init
```

{% endcode %}

If using the uWSGI config file option, the content should look like the sample below

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

```javascript
[uwsgi] 
... 
enable-threads = true 
single-interpreter = true 
import = python_agent.init
```

{% endcode %}

## Gunicorn WSGI <a href="#gunicorn-wsgi" id="gunicorn-wsgi"></a>

When working with Gunicorn WSGI you need to run it with the following a configuration file which contains an import of the SeaLights Python agent in the post\_fork section

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

```javascript
... 
def post_fork(server, worker): 
    import python_agent.init 
...
```

{% endcode %}

## Uvicorn ASGI <a href="#uvicorn-asgi" id="uvicorn-asgi"></a>

Uvicorn does not support importing module to be run before the app is started (as in uwsgi).\
in order to overcome this there is a code change need to be done at the source code in order to init Sealights when Uvicorn is loading

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

```javascript
... 
# Check for an environment variable and import accordingly 
if os.getenv('ENABLE_SEALIGHTS', 'false') == 'true': 
    import python_agent.init     
...
```

{% endcode %}

Running the app:

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

```sh
export ENABLE_SEALIGHTS=true
uvicorn app:APP --host 0.0.0.0 --port 9092 --workers 1 --reload
```

{% endcode %}

<details>

<summary>Sample code for dynamic update of files</summary>

If you don’t want to update your source code, you may evaluate adding these few script lines (or equivalent) in your CI/CD. Usage: `./myscript.sh mypythonfile.py`

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

```python
#!/bin/bash
 
[[ $1 == *.py && -f $1 ]] || { echo "Error: Provide a valid Python file (.py)"; exit 1; }

# Lines to add as an environment variable
LINES_TO_ADD=$(cat <<'EOF'
Check for an environment variable and import accordingly
if os.getenv('ENABLE_SEALIGHTS', 'false') == 'true':
import python_agent.init
EOF
)

# Create a backup and modify the file
cp "$1" "$1.bak" && sed -i "/^import|^from /a\$LINES_TO_ADD" "$1" && echo "[Sealights] Lines inserted into $1, backup created at $1.bak." 
```

{% endcode %}

</details>

## Other servers (Generic solution) <a href="#other-servers-generic-solution" id="other-servers-generic-solution"></a>

For other servers, run with the SeaLights Python agent and the run flags

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

```javascript
sl-python run {--cov-report /path/to/report.xml --labid Lab1} python <your server and args...>
```

{% endcode %}

{% hint style="info" %}
The first parameter after the run command should be an executable file
{% endhint %}

## Containers: Runtime Integration Without Modifying the ENTRYPOINT <a href="#containers-runtime-integration-without-modifying-the-entrypoint" id="containers-runtime-integration-without-modifying-the-entrypoint"></a>

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

```yaml
spec:
  volumes:
    - name: sealights
      emptyDir: {} # Shared volume for the installed `sl-python` binary
  initContainers:
    - name: install-sl-python
      image: python:3.9-slim
      command: ["sh", "-c", "pip install sealights-python-agent && cp $(which sl-python) /sealights/"]
      volumeMounts:
        - name: sealights
          mountPath: /sealights
  containers:
    - name: app-container
      image: python:3.9-slim
      env:
        - name: SEALIGHTS_AGENT_TOKEN
          valueFrom:
            secretKeyRef:
              name: sealights-token-secret
              key: agent-token
        - name: PYTHON_EXE
          value: "/sealights/sl-python run --token \"$SEALIGHTS_AGENT_TOKEN\" -- python"
      command:
        - sh
        - "-c"
        - "$PYTHON_EXE app.py"
      volumeMounts:
        - name: sealights
          mountPath: /sealights
      # Other initialization sections required (e.g. ports, livenessProbe, readinessProbe, etc.)
```

{% endcode %}

## Using a `sitecustomize.py` file

`sitecustomize.py` is a standard Python startup hook that is automatically imported during interpreter initialization (unless Python is started with `-S`). Placing a top-level `sitecustomize.py` on `sys.path` allows to preload the Sealights agent *before any application code is imported*, without modifying the application entrypoint.

### Steps to set up

1. Create the `sitecustomize.py`  with the following content:\
   `import python_agent.init`
2. Place the file in a folder, for example: `/opt/python-startup`
3. Update the PYTHONPATH to include the above folder first, for example:\
   `export PYTHONPATH="/opt/python-startup:${PYTHONPATH}"`&#x20;
4. Set any additional environment variables, for example: `SL_LAB_ID`&#x20;
5. Start your python application as you have till this point

Here is a sample docker file:

<pre><code>FROM python:3.9-slim

...

<strong>RUN mkdir -p /opt/python-startup
</strong>RUN cat > /opt/python-startup/sitecustomize.py &#x3C;&#x3C;'PY'
import python_agent.init
PY

EXPOSE 8080
ENTRYPOINT ["python", "server.py" ]
</code></pre>

Here's a sample k8s yaml env snippet of setting the environment variables:

```
env:
  - name: PYTHONPATH
    value: /opt/python-startup
  - name: SL_LABID
    value: Lab1
```
