# Debugging

Two features of OpenGate let you run your own JavaScript inside the platform:
[connector functions](../device_integration/connector_functions/), which translate what devices say, and
[rules](../management/organizations/channels/rules/), which react to what arrives. Both run server-side, on
events you did not trigger, which makes the usual debugging reflexes useless — there is no console to watch.

This section is that console.

## How it works

```mermaid
flowchart LR
    JS["Your JavaScript<br>connector function or rule"] -->|"logger.info(...)"| SVC["Functions logger<br>service"]
    SVC -->|"WebSocket stream"| YOU["Your terminal<br>or application"]

    classDef mine fill:#addcf8,stroke:#2b7cb8,color:#000
    class JS mine
```

Two halves, one page each:

| Half | What it is | Page |
|---|---|---|
| **Writing** | The `logger` object your script calls: `trace`, `debug`, `info`, `warn`, `error` | [JS Logging API](logger_api/) |
| **Reading** | A WebSocket you open to stream those traces live, filtered by level | [Functions Logger Service](functions_logger/) |

## It covers rules too

The service exposes one endpoint family per subject, and the only difference is the path and the identifier:

| Subject | Endpoint | Identifier |
|---|---|---|
| Connector functions | `.../functions-logger/connectorFunctions/organizations/{org}/channels/{channel}/{cf-id}` | The connector function id |
| Rules | `.../functions-logger/rules/organizations/{org}/channels/{channel}/{rf-id}` | The rule id |

Everything else — the mandatory `X-ApiKey` parameter, the `level` filter and the message format — is
identical for both. See [Functions Logger Service](functions_logger/) for the complete URIs.

## Debugging in practice

A workflow rather than a list of features:

1. **Start with the script disabled.** A connector function's
   [operationalStatus](../device_integration/connector_functions/#when-it-runs-and-on-which-devices) exists
   precisely so a half-written script never touches production devices: create it `DISABLED`, move to `TEST`
   against a test device, and only then to `PRODUCTION`.
2. **Log the inputs you did not expect**, not the ones you did. The `payload` your script receives is
   whatever the device really sent, which is rarely what the datasheet promised.
3. **Subscribe at `TRACE` while you iterate**, then raise the level. Each level includes the ones above it:
   `WARN` delivers `ERROR` and `WARN`, and nothing below.
4. **Remember the REST API barely parses your JavaScript.** A script that was accepted at creation can still
   fail at runtime, and this is where you find out.

{{% notice style="info" title="Levels filter delivery, not writing" icon="lightbulb" %}}
`level` controls what the *service sends you*, not what your script writes. Leaving `logger.trace` calls in
place costs nothing once you stop subscribing at `TRACE`, so there is no reason to strip them out when you
are done debugging.
{{% /notice %}}

{{% children sort="weight" %}}
