Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,10 @@ coverage:
target: 75
flags:
- kyverno
n8n:
target: 75
flags:
- n8n
nvidia_nim:
target: 75
flags:
Expand Down Expand Up @@ -1431,6 +1435,11 @@ flags:
paths:
- mysql/datadog_checks/mysql
- mysql/tests
n8n:
carryforward: true
paths:
- n8n/datadog_checks/n8n
- n8n/tests
nagios:
carryforward: true
paths:
Expand Down
14 changes: 8 additions & 6 deletions .github/workflows/config/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ integration/azure_active_directory:
- azure_active_directory/**/*
integration/azure_iot_edge:
- azure_iot_edge/**/*
integration/barracuda_secure_edge:
- barracuda_secure_edge/**/*
integration/bentoml:
- bentoml/**/*
integration/beyondtrust_identity_security_insights:
Expand Down Expand Up @@ -157,6 +159,8 @@ integration/cloud_foundry_api:
- cloud_foundry_api/**/*
integration/cloudera:
- cloudera/**/*
integration/cloudgen_firewall:
- cloudgen_firewall/**/*
integration/cockroachdb:
- cockroachdb/**/*
integration/cofense_triage:
Expand Down Expand Up @@ -359,10 +363,10 @@ integration/kafka:
- kafka/**/*
integration/kafka_consumer:
- kafka_consumer/**/*
integration/karpenter:
- karpenter/**/*
integration/kandji:
- kandji/**/*
integration/karpenter:
- karpenter/**/*
integration/keda:
- keda/**/*
integration/keeper:
Expand Down Expand Up @@ -467,6 +471,8 @@ integration/mux:
- mux/**/*
integration/mysql:
- mysql/**/*
integration/n8n:
- n8n/**/*
integration/nagios:
- nagios/**/*
integration/network:
Expand Down Expand Up @@ -783,10 +789,6 @@ integration/zerofox_cloud_platform:
- zerofox_cloud_platform/**/*
integration/zk:
- zk/**/*
integration/barracuda_secure_edge:
- barracuda_secure_edge/**/*
integration/cloudgen_firewall:
- cloudgen_firewall/**/*
integration/zscaler_private_access:
- zscaler_private_access/**/*
qa/skip-qa:
Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/test-all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2604,6 +2604,26 @@ jobs:
- py3.13-percona-8.0.42
- py3.13-percona-8.4
fail-fast: false
j636396f:
uses: ./.github/workflows/test-target.yml
with:
job-name: n8n
target: n8n
platform: linux
runner: '["ubuntu-22.04"]'
repo: "${{ inputs.repo }}"
context: ${{ inputs.context }}
python-version: "${{ inputs.python-version }}"
latest: ${{ inputs.latest }}
agent-image: "${{ inputs.agent-image }}"
agent-image-py2: "${{ inputs.agent-image-py2 }}"
agent-image-windows: "${{ inputs.agent-image-windows }}"
agent-image-windows-py2: "${{ inputs.agent-image-windows-py2 }}"
test-py2: ${{ inputs.test-py2 }}
test-py3: ${{ inputs.test-py3 }}
minimum-base-package: ${{ inputs.minimum-base-package }}
pytest-args: ${{ inputs.pytest-args }}
secrets: inherit
j5df646e:
uses: ./.github/workflows/test-target.yml
with:
Expand Down
4 changes: 4 additions & 0 deletions n8n/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# CHANGELOG - n8n

<!-- towncrier release notes start -->

60 changes: 60 additions & 0 deletions n8n/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Agent Check: n8n

## Overview

This check monitors [n8n][1] through the Datadog Agent.

Include a high level overview of what this integration does:
- What does your product do (in 1-2 sentences)?
- What value will customers get from this integration, and why is it valuable to them?
- What specific data will your integration monitor, and what's the value of that data?
Comment on lines +7 to +10
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a meaningful description, or remove these lines.


## Setup

Follow the instructions below to install and configure this check for an Agent running on a host. For containerized environments, see the [Autodiscovery Integration Templates][3] for guidance on applying these instructions.

### Installation

The n8n check is included in the [Datadog Agent][2] package.
No additional installation is needed on your server.

### Configuration

1. Edit the `n8n.d/conf.yaml` file, in the `conf.d/` folder at the root of your Agent's configuration directory to start collecting your n8n performance data. See the [sample n8n.d/conf.yaml][4] for all available configuration options.

2. [Restart the Agent][5].

### Validation

[Run the Agent's status subcommand][6] and look for `n8n` under the Checks section.

## Data Collected

### Metrics

See [metadata.csv][7] for a list of metrics provided by this integration.

### Events

The n8n integration does not include any events.

### Service Checks

The n8n integration does not include any service checks.

See [service_checks.json][8] for a list of service checks provided by this integration.

## Troubleshooting

Need help? Contact [Datadog support][9].


[1]: **LINK_TO_INTEGRATION_SITE**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[1]: **LINK_TO_INTEGRATION_SITE**
[1]: https://n8n.io/

[2]: https://app.datadoghq.com/account/settings/agent/latest
[3]: https://docs.datadoghq.com/containers/kubernetes/integrations/
[4]: https://github.com/DataDog/integrations-core/blob/master/n8n/datadog_checks/n8n/data/conf.yaml.example
[5]: https://docs.datadoghq.com/agent/configuration/agent-commands/#start-stop-and-restart-the-agent
[6]: https://docs.datadoghq.com/agent/configuration/agent-commands/#agent-status-and-information
[7]: https://github.com/DataDog/integrations-core/blob/master/n8n/metadata.csv
[8]: https://github.com/DataDog/integrations-core/blob/master/n8n/assets/service_checks.json
[9]: https://docs.datadoghq.com/help/
44 changes: 44 additions & 0 deletions n8n/assets/configuration/spec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: n8n
files:
- name: n8n.yaml
options:
- template: init_config
options:
- template: init_config/default
- template: instances
options:
- template: instances/openmetrics
overrides:
openmetrics_endpoint.required: true
openmetrics_endpoint.hidden: false
openmetrics_endpoint.display_priority: 1
openmetrics_endpoint.value.example: http://localhost:5678
openmetrics_endpoint.description: |
Endpoint exposing the n8n's metrics in the OpenMetrics format. For more information refer to:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Endpoint exposing the n8n's metrics in the OpenMetrics format. For more information refer to:
Endpoint exposing the n8n's metrics in the OpenMetrics format. For more information, refer to:

https://docs.n8n.io/hosting/logging-monitoring/monitoring/
https://docs.n8n.io/hosting/configuration/environment-variables/endpoints/
raw_metric_prefix.description: |
The prefix prepended to all metrics from n8n.
If not set, the default prefix will be used.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
If not set, the default prefix will be used.
If not set, the default prefix is used.

The default prefix is 'n8n'.
If you are using a custom prefix in n8n through N8N_METRICS_PREFIX, you can set it here.
raw_metric_prefix.value:
display_default: n8n
type: string
example: n8n
raw_metric_prefix.hidden: false
- name: server_port
description: |
The port exposing the HTTP Endpoint of the N8N API.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The port exposing the HTTP Endpoint of the N8N API.
The port exposing the HTTP endpoint of the n8n API.

value:
display_default: 5678
type: integer
- template: logs
example:
- type: file
path: /var/log/n8n/*.log
source: n8n
service: <SERVICE>
- type: docker
source: n8n
service: <SERVICE>
9 changes: 9 additions & 0 deletions n8n/assets/dashboards/n8n_overview.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"title": "N8N Overview Dashboard",
"description": "N8N Overview Dashboard",
"widgets": [],
"template_variables": [],
"layout_type": "ordered",
"notify_list": [],
"reflow_type": "fixed"
}
29 changes: 29 additions & 0 deletions n8n/assets/service_checks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[
{
"agent_version": "7.75.0",
"integration": "n8n",
"check": "n8n.openmetrics.health",
"statuses": ["ok", "critical"],
"groups": [],
"name": "n8n OpenMetrics Health",
"description": "Returns `CRITICAL` if the check cannot access the metrics endpoint. Returns `OK` otherwise."
},
{
"agent_version": "7.75.0",
"integration": "n8n",
"check": "n8n.health.status",
"statuses": ["ok", "critical"],
"groups": [],
"name": "n8n Health Status",
"description": "Returns `CRITICAL` if the health check endpoint returns an unhealthy status. Returns `OK` otherwise."
},
{
"agent_version": "7.75.0",
"integration": "n8n",
"check": "n8n.readiness.status",
"statuses": ["ok", "critical"],
"groups": [],
"name": "n8n Readiness Status",
"description": "Returns `CRITICAL` if the readiness check endpoint returns an unready status. Returns `OK` otherwise."
}
]
1 change: 1 addition & 0 deletions n8n/changelog.d/21835.added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Initial Release
4 changes: 4 additions & 0 deletions n8n/datadog_checks/n8n/__about__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# (C) Datadog, Inc. 2025-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
__version__ = '0.0.1'
7 changes: 7 additions & 0 deletions n8n/datadog_checks/n8n/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# (C) Datadog, Inc. 2025-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
from .__about__ import __version__
from .check import N8nCheck

__all__ = ['__version__', 'N8nCheck']
99 changes: 99 additions & 0 deletions n8n/datadog_checks/n8n/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# (C) Datadog, Inc. 2025-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)

from urllib.parse import urljoin, urlparse # noqa: F401

from datadog_checks.base import AgentCheck, OpenMetricsBaseCheckV2
from datadog_checks.n8n.metrics import METRIC_MAP

DEFAULT_READY_ENDPOINT = '/healthz/readiness'
DEFAULT_HEALTH_ENDPOINT = '/healthz'
DEFAULT_VERSION_ENDPOINT = '/rest/settings'


class N8nCheck(OpenMetricsBaseCheckV2):
__NAMESPACE__ = 'n8n'
DEFAULT_METRIC_LIMIT = 0

def __init__(self, name, init_config, instances=None):
super(N8nCheck, self).__init__(
name,
init_config,
instances,
)
self.openmetrics_endpoint = self.instance["openmetrics_endpoint"]
self.tags = self.instance.get('tags', [])
self._ready_endpoint = DEFAULT_READY_ENDPOINT
self._health_endpoint = DEFAULT_HEALTH_ENDPOINT
self._version_endpoint = DEFAULT_VERSION_ENDPOINT
# Get the N8N API port if specified, otherwise use the default 5678.
self.server_port = str(self.instance.get('server_port', 5678))
self.raw_metric_prefix = self.instance.get('raw_metric_prefix', 'n8n')

def get_default_config(self):
# If raw_metric_prefix is 'n8n', metrics start with 'n8n'
if self.raw_metric_prefix == 'n8n':
namespace = 'n8n'
else:
namespace = f'n8n.{self.raw_metric_prefix}'

return {'namespace': namespace, 'metrics': [METRIC_MAP]}

@AgentCheck.metadata_entrypoint
def _submit_version_metadata(self):
endpoint = urljoin(self.openmetrics_endpoint, self._version_endpoint)
response = self.http.get(endpoint)

if response.ok:
data = response.json()
version = data.get("versionCli", "")
version_split = version.split(".")
if len(version_split) >= 3:
major = version_split[0]
minor = version_split[1]
patch = version_split[2]

version_raw = f'{major}.{minor}.{patch}'

version_parts = {
'major': major,
'minor': minor,
'patch': patch,
}
self.set_metadata('version', version_raw, scheme='semver', part_map=version_parts)
else:
self.log.debug("Malformed N8N Server version format: %s", version)
else:
self.log.debug("Could not retrieve version metadata.")

def _check_n8n_health(self):
endpoint = urljoin(self.openmetrics_endpoint, self._health_endpoint)
response = self.http.get(endpoint)

# Any 4xx or 5xx response from the API endpoint (/healthz) means the n8n process is not responding
if 400 <= response.status_code and response.status_code < 600:
self.service_check('health.status', AgentCheck.CRITICAL, self.tags)
if response.status_code == 200:
self.service_check('health.status', AgentCheck.OK, self.tags)
else:
self.service_check('health.status', AgentCheck.UNKNOWN, self.tags)

def _check_n8n_readiness(self):
endpoint = urljoin(self.openmetrics_endpoint, self._ready_endpoint)
response = self.http.get(endpoint)

# Any 4xx or 5xx response from the API endpoint (/healthz/readiness)
# means the n8n is not ready to accept requests
if 400 <= response.status_code and response.status_code < 600:
self.service_check('health.status', AgentCheck.CRITICAL, self.tags)
if response.status_code == 200:
self.service_check('health.status', AgentCheck.OK, self.tags)
else:
self.service_check('health.status', AgentCheck.UNKNOWN, self.tags)

def check(self, instance):
super().check(instance)
self._submit_version_metadata()
self._check_n8n_health()
self._check_n8n_readiness()
24 changes: 24 additions & 0 deletions n8n/datadog_checks/n8n/config_models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# (C) Datadog, Inc. 2025-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)

# This file is autogenerated.
# To change this file you should edit assets/configuration/spec.yaml and then run the following commands:
# ddev -x validate config -s <INTEGRATION_NAME>
# ddev -x validate models -s <INTEGRATION_NAME>

from .instance import InstanceConfig
from .shared import SharedConfig


class ConfigMixin:
_config_model_instance: InstanceConfig
_config_model_shared: SharedConfig

@property
def config(self) -> InstanceConfig:
return self._config_model_instance

@property
def shared_config(self) -> SharedConfig:
return self._config_model_shared
Loading
Loading