Shopware
Zo monitoren we Shopware-productfeeds met Zabbix
Onlangs werd de Google Shopping-feed van een van onze klanten 's nachts een pak kleiner. Hij verdween niet en gaf ook geen foutmelding. Hij was gewoon veel kleiner dan hij had moeten zijn.
We ontdekten het een dag later, en niet via onze eigen monitoring. Google Merchant Center liet het ons weten. Producten stonden op het punt om uit de Shopping-advertenties te vallen.
Deze keer hadden we geluk. Google geeft je een marge van ongeveer drie dagen voor afgekeurde producten echt pijn doen, dus de feed was opgelost voor het de shop iets kostte. Op geluk willen we echter niet rekenen. Een shop die leeft van Shopping-verkeer mag niet van Google horen dat zijn feed kapot is, en al zeker niet een dag te laat.
Dus naast de feed herstellen, pakten we ook aan hoe we hem opvolgen. In deze post lees je hoe we productfeeds nu monitoren met Zabbix, stap voor stap, inclusief de instellingen en de valkuilen waar we tegenaan liepen. Draai je zelf Zabbix, dan kan je het zo overnemen.
Waarom een krimpende feed er tussendoor glipt
De shop had al monitoring: CPU, geheugen, disk, swap, uptime. Alles bleef groen, want er lag niets plat.
Daarom vallen feedproblemen zo makkelijk niet op. Shopware genereert zijn productexports als bestanden,
geserveerd via een URL zoals /store-api/product-export/<access key>/google.xml. Loopt er iets mis bij dat
genereren, dan krijg je vaak nog steeds:
- Een HTTP 200. De URL werkt, dus een uptime-check is tevreden.
- Geldige XML. Het bestand opent en parset, dus Google aanvaardt het in eerste instantie.
- Gewoon minder producten. Honderden of duizenden items die stilletjes ontbreken.
We weten nog altijd niet exact waarom het gebeurde. Een half afgewerkte exportrun, een timeout tijdens het genereren, een productimport die de zichtbaarheid even veranderde, een cache die een onvolledig bestand serveerde. Allemaal aannemelijk, niets bewezen. Je kan geen check schrijven voor elke mogelijke oorzaak, maar je kan wel het resultaat checken: het bestand werd veel kleiner dan normaal. Een gezonde feed voor deze shop zit rond 19 à 20 MB.
De aanpak: download hem zoals Google dat doet
Elk uur downloadt Zabbix de feed op dezelfde manier als Google Merchant Center, meet hoe groot hij is, en bewaart dat getal. Twee triggers houden het in de gaten:
- Te klein: de feed is meer dan 30% kleiner dan zijn gemiddelde van de voorbije week. Er is iets mis met de inhoud.
- Geen data: Zabbix heeft al 3 uur geen waarde ontvangen. Er is iets mis met de download zelf.
De groottecheck werkt zonder vaste drempel. Hij vergelijkt de feed met zijn eigen geschiedenis, dus de check blijft werken als de catalogus groeit of krimpt, zonder dat iemand hem moet aanpassen.
We gebruiken de Zabbix-server die we al draaien voor alle servers van onze klanten, dus er moest niets nieuws geïnstalleerd worden. Alles hieronder gebeurt in de frontend van Zabbix 6.4, zonder shell-toegang of eigen scripts. Nieuwere versies werken op dezelfde manier, met licht andere menu's.
Stap 1: een HTTP agent item dat de feed meet
Ga naar Data collection → Hosts, open de Items van de host waarop de shop draait, en klik op Create item. We hangen de check aan de host van de shop zelf, zodat de feed naast de rest van de monitoring van die shop staat.
Op het tabblad Item:
| Veld | Waarde | Waarom |
|---|---|---|
| Name | Google feed NL-BE file size | Eén item per feed, dus geef het de naam van de feed |
| Type | HTTP agent | De Zabbix-server haalt de URL zelf op, geen agent nodig |
| Key | feed.size[google] |
Eender welke unieke key; het deel tussen haakjes onderscheidt de feeds |
| Type of information | Numeric (unsigned) | We bewaren een aantal bytes, niet het bestand |
| URL | https://www.example.com/store-api/product-export/<access key>/google.xml |
Exact de URL die je aan Google gaf |
| Request method | GET | |
| Timeout | 60s | Grote feeds hebben tijd nodig; 60s is het maximum in 6.4 |
| Required status codes | 200 | Al de rest maakt het item unsupported |
| Retrieve mode | Body | We hebben het echte bestand nodig, niet alleen de headers |
| Units | B | Zabbix toont dan 19.87 MB in plaats van een kaal getal |
| Update interval | 1h | Vaak genoeg om het nog dezelfde dag te merken, licht voor de shop |
Voeg daarna op het tabblad Preprocessing één stap toe van het type JavaScript:
return value.length;
Zabbix voert preprocessing uit op de server, meteen na de download: de volledige body gaat erin, er komt één getal uit. Enkel dat getal wordt bewaard, dus je database loopt niet elk uur vol met XML-bestanden van 20 MB.
Twee kanttekeningen bij deze aanpak:
value.lengthtelt tekens, geen bytes. Tekens met accenten in Franse producttitels nemen twee bytes in maar tellen als één. Omdat we de feed enkel met zijn eigen eerdere waarden vergelijken, valt dat verschil weg. Heb je byteprecisie nodig, gebruik dan een external check metcurl -w '%{size_download}'.- Waarom niet gewoon
Content-Lengthuitlezen? Je kan Retrieve mode op Headers zetten en die header parsen. Dat is lichter, maar dan ga je uit van wat de server zegt dat hij stuurt. Wij willen weten wat er echt aankomt, dus downloaden we het hele bestand.
Stap 2: test het met Execute now
Zabbix heeft een Test-knop op het itemformulier. Die haalt de waarde op en voert je preprocessing uit, zonder iets op te slaan. Bij onze feed faalde hij met deze melding:
Size of the response received from Zabbix server exceeds the allowed size of 16777216 bytes.
Aan het item zelf scheelt niets. De server downloadde de feed zonder problemen. De limiet komt van het testvenster: de frontend wil je ook de ruwe waarde voor preprocessing tonen, en weigert alles boven 16 MB dat van de server terugkomt. De gewone dataverzameling stuurt de ruwe body nooit naar de frontend, dus daar geldt die limiet niet.
Je kan ZBX_SOCKET_BYTES_LIMIT verhogen in include/defines.inc.php, maar we patchen de frontend liever niet
voor een testvenster. Zo werkt het ook:
- Sla het item op.
- Vink het in de lijst met items aan en klik op Execute now.
- Ga naar Monitoring → Latest data, filter op de host, en zoek je item.
Binnen enkele seconden hadden we onze eerste echte waarde: 19.87 MB. Vanaf nu bewaart Zabbix elk uur een nieuwe waarde, en die waarden vormen de baseline voor de eerste trigger.
Stap 3: twee triggers, twee soorten fouten
Het item verzamelt enkel getallen. Om een melding te krijgen, heb je triggers nodig. Ga naar de Triggers van de host en maak er twee aan.
Trigger 1: de feed is veel kleiner dan normaal. Severity High.
last(/shop-host/feed.size[google])<0.7*avg(/shop-host/feed.size[google],7d:now-1h)
last() neemt de meest recente waarde. avg() is de baseline: de gemiddelde grootte over zeven dagen. Het
stuk :now-1h is een time shift. Daardoor eindigt het venster een uur geleden, zodat de waarde die we
beoordelen niet meetelt in het gemiddelde waarmee we ze vergelijken.
Waarom 30% en waarom een week:
- 30% ligt ver buiten de normale schommelingen (een solden-actie die afloopt, een categorie die offline gaat), en vangt toch een feed die een groot deel van zijn producten kwijt is.
- Een week is lang genoeg zodat een kapotte feed zijn eigen baseline niet meteen mee omlaag trekt. Met een check per uur blijft een feed die op de helft van zijn grootte vastzit dagenlang een probleem, in plaats van dat het probleem 's nachts vanzelf verdwijnt omdat het gemiddelde mee gezakt is. Een week vlakt ook patronen per weekdag uit, zoals een catalogus die op maandag verandert.
Zorg dat het item zijn history langer dan zeven dagen bijhoudt, anders heeft de baseline niets om mee te werken. De standaardinstelling doet dat. Bij een nieuw item is het gemiddelde nog op maar een paar waarden gebaseerd, dus geef het een dag voor je erop vertrouwt.
Twee kleine toevoegingen maken de melding nuttiger:
- Operational data:
Size: {ITEM.LASTVALUE1}, zodat de melding de echte grootte toont. - URL: de URL van de feed zelf, zodat wie het oppikt de feed met één klik kan openen.
Trigger 2: de check zelf werkt niet meer. Severity Warning.
nodata(/shop-host/feed.size[google],3h)=1
Deze vergeet je snel. Loopt de download in een timeout, geeft hij een 500 terug, of ligt de shop plat, dan
wordt het item unsupported en komt er geen nieuwe waarde binnen. Trigger 1 blijft dan de laatste goede
waarde evalueren en gaat niet af. nodata() vangt dat op: drie uur geen waarde betekent drie gemiste checks
op rij.
We taggen beide triggers met component: feed, zodat ze makkelijk te filteren zijn in de Problems-weergave en
in actions.
Stap 4: zorg dat de melding iemand bereikt
Een trigger helpt pas als iemand de melding krijgt. Controleer in Alerts → Actions → Trigger actions dat er
een action is die de nieuwe triggers dekt. Een algemene action die je admin-groep verwittigt bij elk probleem
volstaat. Stuur je meldingen door per klant of per severity, voeg dan een voorwaarde toe op de tag
component: feed of op de host.
Controleer daarna de media van de gebruikers die de melding moeten krijgen. Staat hun e-mail- of Slack-media ingesteld op enkel severity Disaster, dan komt een probleem met severity High niet bij hen aan.
Meer feeds, dezelfde check
De meeste shops hebben meer dan één feed: één per verkoopkanaal, één per taal, soms één per marketplace. Onze klant heeft er drie. Zodra het eerste item werkt, gaat de rest snel:
- Open het item en klik op Clone.
- Pas de naam, de key (
feed.size[google_fr],feed.size[google_frbe], …) en de URL aan. - Sla op, en maak dan de twee triggers aan voor de nieuwe key.
Preprocessing, interval en timeout komen mee met de kloon, dus enkel de URL kan je nog fout invullen. Omdat de drempel relatief is, moet je ook per feed geen getal kiezen: een marketplace-feed van 2 MB en een Google-feed van 20 MB gebruiken exact dezelfde trigger. Klik één keer per feed op Execute now om te bevestigen dat elke feed een redelijke waarde teruggeeft.
Varianten en beperkingen
Deze setup is gemaakt om een feed te vangen die plots een groot deel van zijn inhoud verliest. Een paar dingen doet hij niet:
- Hij vangt plotse dalingen, geen geleidelijke achteruitgang. De baseline volgt de feed. Een feed die een maand lang elke dag 1% verliest, lijkt nooit 30% kleiner dan vorige week, dus de trigger gaat nooit af. In onze ervaring gaan feeds plots kapot, dus nemen we dat erbij, in ruil voor een drempel die we nooit moeten aanpassen.
- Geplande wijzigingen gaan ook af. Sluit je een verkoopkanaal of haal je de helft van de catalogus weg, dan kan de trigger dat niet onderscheiden van een kapotte export. Zet Allow manual close aan op de trigger, zodat je het probleem kan sluiten zodra je bevestigd hebt dat de daling gewild is. De baseline haalt het binnen de week in.
- Grootte is een benadering voor het aantal producten. Tel je liever items, pas dan de preprocessing aan
om
<item>-elementen te tellen en alarmeer daarop. Dat is preciezer, maar voor grote feeds iets zwaarder voor de Zabbix-server. - De inhoud wordt niet gevalideerd. Foute prijzen of kapotte afbeeldings-URL's veranderen niets aan de grootte. Daarvoor kijk je best naar de diagnostiek in Merchant Center.
- De timeout van 60 seconden is een harde grens in Zabbix 6.4. Duurt het langer om een feed te
serveren, dan laat de
nodata()-trigger het je weten, en ligt de oplossing meestal in hoe de feed gegenereerd en gecachet wordt, niet in Zabbix.
Standaard bij elk project
We bouwden dit niet voor één shop. Deze checks maken nu deel uit van onze standaard monitoringstack voor elk Shopware-project dat we hosten of onderhouden. Elke productfeed die een klant naar Google Shopping of een ander verkoopkanaal stuurt, krijgt:
- elk uur een download en groottecheck,
- een "te klein"-trigger die de feed vergelijkt met zijn eigen voorbije week,
- een "geen data"-trigger voor wanneer de download zelf faalt,
- meldingen die naar ons team gaan.
Krimpt een feed opnieuw 's nachts, dan willen we het binnen het uur weten en het opgelost hebben voor Google het merkt.
Gaat je productfeed vannacht kapot, merk jij het dan voor Google het doet? Twijfel je, dan bekijken we graag je setup. Monitoring zit in elk project dat we opnemen, en we voegen je feeds er met plezier aan toe.
Laten we praten
Een e-commerce project in gedachten?
Wij zijn een boutique e-commerce bureau. Vertel ons wat je bouwt en we helpen je sneller vooruit.