The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "Marcel - Monitoring Syst\u00e8me",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "*/5 * * * *"
}
]
}
},
"id": "f8b8c8e0-5234-4567-8901-000000000001",
"name": "Surveillance Syst\u00e8me",
"type": "n8n-nodes-base.cron",
"typeVersion": 1,
"position": [
240,
300
]
},
{
"parameters": {
"jsCode": "// V\u00e9rifier l'\u00e9tat des services Docker\nconst { execSync } = require('child_process');\n\ntry {\n // V\u00e9rifier les conteneurs Docker\n const containers = execSync('docker ps --format \"table {{.Names}}\\t{{.Status}}\\t{{.Ports}}\"', { encoding: 'utf8' });\n \n // V\u00e9rifier l'utilisation des ressources\n const stats = execSync('docker stats --no-stream --format \"table {{.Container}}\\t{{.CPUPerc}}\\t{{.MemUsage}}\"', { encoding: 'utf8' });\n \n // V\u00e9rifier l'espace disque\n const disk = execSync('df -h /', { encoding: 'utf8' });\n \n // V\u00e9rifier la charge syst\u00e8me\n const load = execSync('uptime', { encoding: 'utf8' });\n \n return {\n timestamp: new Date().toISOString(),\n containers: containers,\n stats: stats,\n disk: disk,\n load: load,\n status: 'healthy'\n };\n} catch (error) {\n return {\n timestamp: new Date().toISOString(),\n error: error.message,\n status: 'error'\n };\n}"
},
"id": "f8b8c8e0-5234-4567-8901-000000000002",
"name": "V\u00e9rifier \u00c9tat Syst\u00e8me",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "condition1",
"leftValue": "={{ $json.status }}",
"rightValue": "error",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "or"
},
"options": {}
},
"id": "f8b8c8e0-5234-4567-8901-000000000003",
"name": "Probl\u00e8me D\u00e9tect\u00e9 ?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
680,
200
]
},
{
"parameters": {
"operation": "insert",
"table": "notifications",
"columns": "type_notification, titre, message, priorite, canaux",
"additionalFields": {
"type_notification": "systeme",
"titre": "\ud83d\udea8 Probl\u00e8me syst\u00e8me d\u00e9tect\u00e9",
"message": "\u26a0\ufe0f **Alerte Marcel**\\n\\n\ud83d\udda5\ufe0f Un probl\u00e8me a \u00e9t\u00e9 d\u00e9tect\u00e9 sur le syst\u00e8me:\\n\\n```\\n{{ $json.error || 'Erreur inconnue' }}\\n```\\n\\n\ud83d\udd27 V\u00e9rifiez les logs syst\u00e8me et les services Docker.",
"priorite": "critique",
"canaux": [
"telegram",
"email"
]
}
},
"id": "f8b8c8e0-5234-4567-8901-000000000004",
"name": "Alerte Syst\u00e8me",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.4,
"position": [
900,
120
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "insert",
"table": "metriques",
"columns": "nom_metrique, valeur, unite, tags",
"additionalFields": {
"nom_metrique": "system_health",
"valeur": "{{ $json.status === 'healthy' ? 1 : 0 }}",
"unite": "boolean",
"tags": "{{ JSON.stringify({service: 'marcel', type: 'health_check'}) }}"
}
},
"id": "f8b8c8e0-5234-4567-8901-000000000005",
"name": "Enregistrer M\u00e9triques",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.4,
"position": [
680,
400
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "*/10 * * * *"
}
]
}
},
"id": "f8b8c8e0-5234-4567-8901-000000000006",
"name": "V\u00e9rification Base Donn\u00e9es",
"type": "n8n-nodes-base.cron",
"typeVersion": 1,
"position": [
240,
600
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT \n 'database_size' as metric,\n pg_size_pretty(pg_database_size(current_database())) as size,\n pg_database_size(current_database()) as size_bytes,\n (SELECT count(*) FROM medicaments) as medicaments_count,\n (SELECT count(*) FROM prises_medicaments WHERE date_prise >= CURRENT_DATE) as prises_today,\n (SELECT count(*) FROM notifications WHERE statut = 'en_attente') as notifications_pending,\n (SELECT count(*) FROM conversations WHERE created_at >= CURRENT_DATE) as conversations_today",
"options": {}
},
"id": "f8b8c8e0-5234-4567-8901-000000000007",
"name": "Statistiques BDD",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.4,
"position": [
460,
600
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Analyser les statistiques et cr\u00e9er des m\u00e9triques\nconst stats = $json;\n\n// Cr\u00e9er un tableau de m\u00e9triques\nconst metriques = [\n {\n nom: 'database_size_bytes',\n valeur: stats.size_bytes,\n unite: 'bytes',\n tags: {service: 'postgresql', type: 'storage'}\n },\n {\n nom: 'medicaments_total',\n valeur: stats.medicaments_count,\n unite: 'count',\n tags: {service: 'marcel', type: 'medicaments'}\n },\n {\n nom: 'prises_today',\n valeur: stats.prises_today,\n unite: 'count',\n tags: {service: 'marcel', type: 'prises', period: 'daily'}\n },\n {\n nom: 'notifications_pending',\n valeur: stats.notifications_pending,\n unite: 'count',\n tags: {service: 'marcel', type: 'notifications'}\n },\n {\n nom: 'conversations_today',\n valeur: stats.conversations_today,\n unite: 'count',\n tags: {service: 'marcel', type: 'conversations', period: 'daily'}\n }\n];\n\nreturn metriques.map(m => ({\n nom_metrique: m.nom,\n valeur: m.valeur,\n unite: m.unite,\n tags: JSON.stringify(m.tags)\n}));"
},
"id": "f8b8c8e0-5234-4567-8901-000000000008",
"name": "Pr\u00e9parer M\u00e9triques BDD",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
680,
600
]
},
{
"parameters": {
"operation": "insert",
"table": "metriques",
"columns": "nom_metrique, valeur, unite, tags",
"additionalFields": {},
"options": {}
},
"id": "f8b8c8e0-5234-4567-8901-000000000009",
"name": "Sauvegarder M\u00e9triques BDD",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.4,
"position": [
900,
600
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 20 * * *"
}
]
}
},
"id": "f8b8c8e0-5234-4567-8901-000000000010",
"name": "Rapport Quotidien",
"type": "n8n-nodes-base.cron",
"typeVersion": 1,
"position": [
240,
800
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT \n DATE(created_at) as date,\n COUNT(*) as total_conversations,\n COUNT(CASE WHEN type_interaction = 'medicament' THEN 1 END) as conversations_medicament,\n COUNT(CASE WHEN type_interaction = 'rdv' THEN 1 END) as conversations_rdv,\n COUNT(CASE WHEN type_interaction = 'administratif' THEN 1 END) as conversations_admin\nFROM conversations \nWHERE created_at >= CURRENT_DATE - INTERVAL '7 days'\nGROUP BY DATE(created_at)\nORDER BY date DESC",
"options": {}
},
"id": "f8b8c8e0-5234-4567-8901-000000000011",
"name": "Statistiques Semaine",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.4,
"position": [
460,
800
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// G\u00e9n\u00e9rer le rapport hebdomadaire\nconst stats = $input.all();\n\nif (stats.length === 0) {\n return {\n message: \"\ud83d\udcca **Rapport Marcel - Semaine**\\n\\n\u274c Aucune donn\u00e9e disponible pour cette semaine.\"\n };\n}\n\nlet message = \"\ud83d\udcca **Rapport Marcel - Semaine du \" + new Date().toLocaleDateString('fr-FR') + \"**\\n\\n\";\n\n// Calculer les totaux\nlet totalConversations = 0;\nlet totalMedicaments = 0;\nlet totalRdv = 0;\nlet totalAdmin = 0;\n\nstats.forEach(day => {\n const data = day.json;\n totalConversations += data.total_conversations;\n totalMedicaments += data.conversations_medicament;\n totalRdv += data.conversations_rdv;\n totalAdmin += data.conversations_admin;\n});\n\nmessage += \"\ud83d\udcc8 **R\u00e9sum\u00e9 de la semaine:**\\n\";\nmessage += `\ud83d\udcac Total conversations: ${totalConversations}\\n`;\nmessage += `\ud83d\udc8a Questions m\u00e9dicaments: ${totalMedicaments}\\n`;\nmessage += `\ud83c\udfe5 Gestion RDV: ${totalRdv}\\n`;\nmessage += `\ud83d\udccb T\u00e2ches admin: ${totalAdmin}\\n\\n`;\n\nmessage += \"\ud83d\udcc5 **D\u00e9tail par jour:**\\n\";\nstats.slice(0, 7).forEach(day => {\n const data = day.json;\n const date = new Date(data.date).toLocaleDateString('fr-FR', {weekday: 'short', day: '2-digit', month: '2-digit'});\n message += `${date}: ${data.total_conversations} conversations\\n`;\n});\n\n// Ajouter des insights\nmessage += \"\\n\ud83d\udca1 **Insights:**\\n\";\nif (totalMedicaments > totalConversations * 0.5) {\n message += \"\u2022 Focus principal sur la gestion des m\u00e9dicaments\\n\";\n}\nif (totalRdv > 5) {\n message += \"\u2022 Activit\u00e9 \u00e9lev\u00e9e de gestion des rendez-vous\\n\";\n}\nif (totalConversations < 10) {\n message += \"\u2022 Utilisation mod\u00e9r\u00e9e cette semaine\\n\";\n} else if (totalConversations > 50) {\n message += \"\u2022 Utilisation intensive de Marcel cette semaine\\n\";\n}\n\nmessage += \"\\n\ud83d\ude80 Marcel continue de vous assister efficacement !\";\n\nreturn {\n message: message,\n total_conversations: totalConversations,\n week_stats: {\n medicaments: totalMedicaments,\n rdv: totalRdv,\n admin: totalAdmin\n }\n};"
},
"id": "f8b8c8e0-5234-4567-8901-000000000012",
"name": "G\u00e9n\u00e9rer Rapport",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
680,
800
]
},
{
"parameters": {
"operation": "insert",
"table": "notifications",
"columns": "type_notification, titre, message, priorite, canaux",
"additionalFields": {
"type_notification": "systeme",
"titre": "\ud83d\udcca Rapport hebdomadaire Marcel",
"message": "{{ $json.message }}",
"priorite": "normale",
"canaux": [
"telegram"
]
}
},
"id": "f8b8c8e0-5234-4567-8901-000000000013",
"name": "Envoyer Rapport",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.4,
"position": [
900,
800
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 3 * * 0"
}
]
}
},
"id": "f8b8c8e0-5234-4567-8901-000000000014",
"name": "Nettoyage Logs",
"type": "n8n-nodes-base.cron",
"typeVersion": 1,
"position": [
240,
1000
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "-- Nettoyer les anciens logs\nDELETE FROM logs_systeme WHERE created_at < NOW() - INTERVAL '30 days';\n\n-- Nettoyer les anciennes m\u00e9triques\nDELETE FROM metriques WHERE timestamp < NOW() - INTERVAL '90 days';\n\n-- Nettoyer les anciennes conversations\nDELETE FROM conversations WHERE created_at < NOW() - INTERVAL '365 days';\n\n-- Optimiser les tables\nVACUUM ANALYZE logs_systeme;\nVACUUM ANALYZE metriques;\nVACUUM ANALYZE conversations;",
"options": {}
},
"id": "f8b8c8e0-5234-4567-8901-000000000015",
"name": "Nettoyer Base",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.4,
"position": [
460,
1000
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "insert",
"table": "logs_systeme",
"columns": "niveau, module, message, details",
"additionalFields": {
"niveau": "info",
"module": "maintenance",
"message": "Nettoyage automatique des donn\u00e9es anciennes effectu\u00e9",
"details": "{{ JSON.stringify({action: 'cleanup', date: new Date().toISOString()}) }}"
}
},
"id": "f8b8c8e0-5234-4567-8901-000000000016",
"name": "Log Nettoyage",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.4,
"position": [
680,
1000
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
}
],
"connections": {
"Surveillance Syst\u00e8me": {
"main": [
[
{
"node": "V\u00e9rifier \u00c9tat Syst\u00e8me",
"type": "main",
"index": 0
}
]
]
},
"V\u00e9rifier \u00c9tat Syst\u00e8me": {
"main": [
[
{
"node": "Probl\u00e8me D\u00e9tect\u00e9 ?",
"type": "main",
"index": 0
},
{
"node": "Enregistrer M\u00e9triques",
"type": "main",
"index": 0
}
]
]
},
"Probl\u00e8me D\u00e9tect\u00e9 ?": {
"main": [
[
{
"node": "Alerte Syst\u00e8me",
"type": "main",
"index": 0
}
]
]
},
"V\u00e9rification Base Donn\u00e9es": {
"main": [
[
{
"node": "Statistiques BDD",
"type": "main",
"index": 0
}
]
]
},
"Statistiques BDD": {
"main": [
[
{
"node": "Pr\u00e9parer M\u00e9triques BDD",
"type": "main",
"index": 0
}
]
]
},
"Pr\u00e9parer M\u00e9triques BDD": {
"main": [
[
{
"node": "Sauvegarder M\u00e9triques BDD",
"type": "main",
"index": 0
}
]
]
},
"Rapport Quotidien": {
"main": [
[
{
"node": "Statistiques Semaine",
"type": "main",
"index": 0
}
]
]
},
"Statistiques Semaine": {
"main": [
[
{
"node": "G\u00e9n\u00e9rer Rapport",
"type": "main",
"index": 0
}
]
]
},
"G\u00e9n\u00e9rer Rapport": {
"main": [
[
{
"node": "Envoyer Rapport",
"type": "main",
"index": 0
}
]
]
},
"Nettoyage Logs": {
"main": [
[
{
"node": "Nettoyer Base",
"type": "main",
"index": 0
}
]
]
},
"Nettoyer Base": {
"main": [
[
{
"node": "Log Nettoyage",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {
"executionOrder": "v1"
},
"versionId": "1",
"meta": {
"templateCredsSetupCompleted": true
},
"id": "marcel-monitoring",
"tags": [
{
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z",
"id": "marcel-system",
"name": "Marcel Syst\u00e8me"
}
]
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
postgres
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Marcel - Monitoring Système. Uses postgres. Scheduled trigger; 16 nodes.
Source: https://github.com/EpicSanDev/MARCEL/blob/83184adb16a52a1b39a4a118ab7e10aa6e236200/workflows/05-monitoring.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Disparador 1.8. Uses itemLists, postgres, emailSend, httpRequest. Scheduled trigger; 85 nodes.
공유회_알림톡_크론. Uses postgres, httpRequest, n8n-nodes-solapi. Scheduled trigger; 39 nodes.
QuepasaAutomatic. Uses postgres, postgresTrigger, httpRequest. Scheduled trigger; 39 nodes.
QuepasaAutomatic. Uses postgres, postgresTrigger, httpRequest. Scheduled trigger; 39 nodes.
QuepasaAutomatic. Uses postgres, postgresTrigger, httpRequest. Scheduled trigger; 39 nodes.