Native Observability
Native Observability è nato il 12 febbraio 2026 da una domanda pratica: capire cosa stesse facendo Drupal in produzione su un sito dove non potevo installare un agente esterno. L'ho scritto io, e su drupal.org ne sono l'unico maintainer, quindi ogni confronto con altri strumenti che trovi in questa pagina va letto sapendo questo. I dati sui moduli alternativi sono presi dalle rispettive pagine di progetto il 24 settembre 2026 e sono verificabili uno per uno; il giudizio su quando serve un modulo invece di un altro è mio, e lo trovi separato dai dati.
Chi sviluppa Native Observability, e da quando
Con che cosa è costruito Native Observability
Quale problema risolve Native Observability
In Drupal non esiste un modo nativo di sapere quale rotta è lenta. La domanda «perché il mio sito è lento, da dove comincio» ricorre sul forum di drupal.org dal 2007 al 2015 almeno sei volte, e la risposta indicizzata è sempre la stessa: disabilita i moduli uno alla volta, guarda il dblog, guarda lo slow query log di MySQL. Fra il profiler da sviluppo, che si spegne in produzione, e l'APM commerciale, che richiede un agente sul server e un abbonamento, non c'è niente. Chi non può installare un'estensione PHP sul server di produzione, o non vuole mandare i dati fuori, resta senza strumenti.
Come Native Observability risolve il problema
Native Observability strumenta Drupal avvolgendo i servizi del core invece di applicare patch: un decorator su `http_client`, un observer su `cache_tags.invalidator`, un middleware attorno a `page_cache` e alcuni kernel event subscriber. Da lì raccoglie le tracce con identificativo ULID e collega ogni richiesta figlia a quella che l'ha generata, comprese le chiamate AJAX. Sulla stessa richiesta costruisce gli span di esecuzione, osserva cache e database, e aggrega le metriche per rotta. I dati restano dentro Drupal e si leggono in una dashboard interna, oppure escono verso Prometheus, Elastic o un collector OpenTelemetry. La famiglia è divisa in undici sottomoduli e tre tier di installazione, uno per profilo di consumo, ciascuno con un comando Drush.
Che risultati ha dato Native Observability
Il modulo è alla release stabile 2.0.1 del 21 settembre 2026, dichiara compatibilità con Drupal 10 e 11, richiede PHP 8.2 o superiore ed è coperto dalla security advisory policy di drupal.org. Alla stessa data drupal.org riporta dodici siti che lo usano e due issue aperte, entrambe di documentazione o compatibilità futura, nessun bug funzionale. La versione 2.0.0 ha rimosso la stima di overhead che il modulo pubblicava prima e l'ha sostituita con una misura che ogni installazione esegue per conto proprio.
Che cosa registra Native Observability
Il modulo registra cinque famiglie di dati, tutte legate alla singola richiesta HTTP.
Tracce
Ogni richiesta riceve un identificativo ULID, e le richieste figlie, comprese quelle AJAX, vengono correlate alla richiesta che le ha generate. L'identificativo di correlazione viene anche restituito in un header della risposta, quindi è recuperabile da fuori.
Span di esecuzione
I tempi dei servizi eseguiti durante la richiesta, categorizzati e visualizzabili per traccia. Le chiamate HTTP in uscita vengono osservate da un middleware sullo handler stack di Guzzle, quindi entra nella traccia ogni richiesta fatta attraverso l'http_client di Drupal, senza toccare il modulo che la esegue.
Metriche per rotta
Volume di richieste, durata media e due percentili, aggregati per rotta e non per URL.
Il percentile dice quanto è lenta la pagina per chi sta peggio. Il P95 è il tempo sotto il quale restano 95 richieste su 100: se vale 800 millisecondi, cinque richieste su cento hanno impiegato di più. Il P99 alza l'asticella a 99 su 100 e fotografa la coda peggiore. Servono perché la media nasconde proprio quelle: novantacinque pagine veloci e cinque lentissime danno una media rassicurante e un sito che qualcuno trova inutilizzabile.
Aggregare per rotta, e non per URL, è ciò che rende confrontabili due pagine dello stesso tipo con contenuti diversi.
Eventi di cache
Comportamento reale del livello di cache delle risposte, cacheabilità e invalidazioni per tag, ciascuno con un report filtrabile e un export JSON.
Come si leggono questi eventi su richieste vere, compreso il HIT della page cache che Drupal non gestisce, è spiegato nell'articolo perché una pagina Drupal non va in cache.
Query di database
Le query lente o comunque rilevanti, con la soglia decisa da slow_query_threshold_ms e un tetto per richiesta deciso da max_stored_queries_per_request, entrambi in native_observability_database_observer.settings.
Requisiti e compatibilità
| Requisito | Valore |
|---|---|
| Drupal | 10 oppure 11, dichiarato su ogni modulo della famiglia |
| PHP | 8.2 o superiore |
| Database | qualunque database supportato da Drupal core |
| Release stabile corrente | 2.0.1, 21 settembre 2026 |
| Security advisory policy | coperto |
Il limite su PHP 8.2 non è prudenza: il modulo usa classi readonly, che PHP 8.1 non riesce a interpretare. Drupal 10 accetta ancora PHP 8.1, quindi su quella major il modulo è più restrittivo del core, e composer.json rifiuta l'installazione all'inizio invece di lasciarla fallire dopo.
Sul database c'è un solo caso particolare. La dashboard ordina i campioni con una window function, e MySQL 5.7 è l'unico server ammesso da Drupal che non ne ha. Riguarda solo Drupal 10, perché Drupal 11 richiede già MySQL 8.0. Su MySQL 5.7 l'ordinamento si sposta in PHP, le pagine continuano a funzionare, e lo status report lo dichiara.
Come si installa
L'installazione si fa con Composer e poi con uno dei tre comandi Drush che installano un tier intero.
composer require drupal/native_observability
drush en native_observability -yIl secondo comando serve la prima volta e non è una formalità: Drush scopre i comandi di un modulo solo dopo che quel modulo è abilitato, quindi su un sito pulito i comandi drush no:preset:* non esistono ancora.
| Tier | Per chi | Comando |
|---|---|---|
raw |
scraper esterni, Prometheus, Mimir, CI. Nessuna interfaccia | drush no:preset:raw |
dashboard |
chi amministra il sito e legge i dati dentro Drupal | drush no:preset:dashboard |
integrations |
chi spinge la telemetria verso uno stack esterno via OTLP, o collega gli eventi a ECA | drush no:preset:integrations |
Ogni preset è idempotente: rieseguirlo su un sito già configurato stampa «Already enabled» per i moduli noti ed esce senza errore.
Perché il modulo può rifiutare di installarsi
Native Observability avvolge i servizi del core invece di applicare patch, e questo lascia spazio a un problema preciso: un altro modulo che decora o ri-tagga lo stesso servizio può prendere silenziosamente il sopravvento. La strumentazione smetterebbe di vedere una parte dei dati senza che compaia nessun errore, e i grafici continuerebbero a disegnarsi, semplicemente incompleti.
Il sanity check risponde a una domanda sola: la strumentazione è davvero agganciata? Elenca ogni punto di integrazione che la famiglia installa, conferma che sia l'implementazione attiva, e segnala qualunque altro modulo stia competendo per lo stesso punto. Si raggiunge da /admin/reports/native-observability/sanity-check o con drush no:sanity-check.
Quando trova una sovrascrittura incompatibile, il modulo base e tutti i sottomoduli rifiutano di installarsi. Uno strumento di misura che misura male è peggio di uno strumento assente, perché nessuno ha motivo di dubitare dei suoi numeri.
Quanto costa, e chi lo misura
Il costo del modulo lo misuri tu, sul tuo server, con un comando che il modulo stesso porta con sé. Non c'è una percentuale da credere sulla parola, perché una percentuale misurata altrove non descrive la tua installazione.
drush no:overhead:measureLa misura confronta due stati dello stesso sito, alterna i blocchi, lavora su differenze appaiate con un test di significatività deterministico, scarta il riscaldamento e dichiara cosa non è compreso nel numero. Il modulo porta due rotte di calibrazione apposite, chiuse fuori da una misura: una che non esegue nessuna query e nessun rendering, e una che esegue un carico dichiarato e costante. Servono a due cose: far sì che la stessa misura ponga la stessa domanda su qualunque installazione, e rendere confrontabili due esecuzioni sullo stesso sito.
Due macchine, due numeri diversi
La stessa misura, con lo stesso protocollo, su due macchine mie dà 4,684 e 6,953 millisecondi per richiesta. Non è un errore di una delle due: è il motivo per cui il modulo ha smesso di pubblicare una cifra unica.
Il primo numero viene dalla macchina di sviluppo su cui è nato il modulo, ed è quello riportato nella documentazione, con la sua tabella di provenienza. Ripetendo la misura otto volte in due giorni, da 9 a 15 coppie per volta, lì la forchetta è stata da 4,59 a 5,72 millisecondi.
Il secondo viene da un ambiente DDEV in container su un iMac, Drupal 11.4.5 e PHP 8.3, misurato il 25 settembre 2026 con Xdebug spento, perché Xdebug strumenta ogni chiamata di funzione PHP e qualunque misura fatta con lui acceso non vale niente. Questo è l'output, tagliato alle righe che contano:
Fixed cost per request (a): 6.953 ms/req
| Workload | OFF | ON | Delta | Verdict |
| calibration-minimal | 3.778 ms | 10.757 | 6.953 | meas |
| calibration-calibrated | 22.476 ms | 30.279 | 7.707 | meas |
calibration-minimal:
- budget: 0.87% of the declared TTFB budget (good)
- N 15 | IQR [6.908, 7.020] | noise 0.040 | signs 7/7 | p=0.01562Le due righe che rendono leggibile il numero sono le ultime. Il rumore di fondo della macchina è 0,040 millisecondi e l'effetto misurato è 6,953: il segnale sta centosettantatré volte sopra il rumore, con il test dei segni a 7 su 7 e p = 0,01562. Un delta che non superasse il rumore lo strumento lo marcherebbe unclear invece di meas, e non lo pubblicherei.
Contro un budget di risposta di 800 millisecondi sono lo 0,87%, ma quel denominatore resta mio: va sostituito col budget del tuo sito.
Il costo non cresce col carico
Le due rotte di calibrazione eseguono lavoro diverso, e il costo del modulo fra le due non cambia in modo misurabile: la differenza è 0,754 millisecondi su 20 unità dichiarate, con p = 0,125 contro una soglia di rumore di 0,293. Lo strumento non la arrotonda a zero e non la spaccia per un risultato positivo, la dichiara non risolta e spiega cosa vuol dire:
> This is a result, not a failure: it means the cost does not grow with the > declared load, as far as this run can resolve.
In pratica: il modulo costa una cifra fissa per richiesta, e non di più su una pagina che lavora di più. Se ti serve risolvere quella differenza, il comando accetta più coppie per alzare la potenza del test.
Il numero che non troverai qui
La tabella riporta anche +184,05% sulla rotta minimale, e quella percentuale non va letta. La legenda dello strumento lo dice da sé: la rotta di calibrazione minimale non esegue query né rendering, quindi il suo denominatore è artificialmente piccolo e la percentuale che ne esce non descrive nessuna pagina reale. Va letto il delta assoluto, e la quota sul budget della tua pagina.
Cosa ha osservato chi l'ha messo in produzione
Sotto l'episodio di Talking Drupal dedicato al modulo, un lettore ha raccontato di averlo installato su un sito di produzione che serve circa cento pagine al minuto e di averlo tenuto acceso un paio di giorni, senza percepire nessun calo di prestazioni. Nello stesso commento segnala un effetto che pesa di più: il database è cresciuto di tre o quattro volte.
È esattamente ciò che deve succedere. Un modulo che registra cosa succede a ogni richiesta scrive righe, e quelle righe occupano spazio su disco. La discussione pubblica su questo modulo ha parlato quasi solo di millisecondi: chi lo mette in esercizio si accorge prima del disco.
Come si tiene sotto controllo lo spazio
| Impostazione | Valore predefinito | Cosa limita |
|---|---|---|
retention.max_rows |
50.000 | tetto di righe su tracce, span, eventi di cache e query |
trace_retention_hours |
72 | da quante ore le tracce vengono cancellate |
spans_retention_hours |
24 | idem per gli span |
metrics_retention_days |
7 | idem per le metriche aggregate |
max_stored_queries_per_request |
20 | quante query si conservano per richiesta |
max_stored_invalidations_per_request |
50 | quante invalidazioni di cache per richiesta |
C'è anche un interruttore generale, capture.enabled: spegnendolo il modulo smette di registrare senza essere disinstallato, e i dati già raccolti restano disponibili per l'analisi. È il modo previsto per accendere l'osservazione su una finestra di tempo, spegnerla, e lavorare con calma su ciò che è stato raccolto.
Perché il numero prima non c'era
Fino alla versione 1.1.x il modulo pubblicava «Estimated overhead: 10%», una percentuale ottenuta sommando quattro costanti scritte nel codice: nessuna delle quattro era stata misurata, e la cifra non descriveva nessuna installazione reale, compresa quella di chi la leggeva. La versione 2.0.0 ha cancellato quel codice. Dopo l'aggiornamento la sezione dell'overhead nel report parte nascosta, e ricompare solo quando una misura è stata davvero eseguita.
Come si colloca rispetto agli altri strumenti
Native Observability non è un profiler, è una scatola nera. La distinzione non è di marketing e cambia chi ha davanti lo strumento.
Un profiler lo accendi quando stai indagando: sei tu alla tastiera, riproduci il problema, e in cambio ottieni un dettaglio che qui non troverai. XHProf scompone il tempo per funzione, con l'albero di chi chiama chi. Native Observability cronometra i servizi e si ferma lì.
Una scatola nera invece era già accesa quando la cosa è successa. Registra meno, e tutto il suo valore sta nel non aver dovuto prevedere il guasto. È la differenza fra chiedersi «perché questa pagina è lenta mentre la guardo» e «perché quella richiesta di ieri, che non riesco a riprodurre, ci ha messo sei secondi».
Dati letti dalle pagine di progetto su drupal.org il 24 settembre 2026.
| Strumento | Ultima release | Siti | Security policy | Cosa misura |
|---|---|---|---|---|
webprofiler |
11.2.3, 9 settembre 2026 | 1.164 | coperto | una richiesta per volta, da una toolbar sulla pagina che stai guardando |
monitoring |
8.x-1.22, 9 luglio 2026 | 2.595 | coperto | la salute del sito con sensori, non la latenza per rotta |
opentelemetry |
1.0.0-beta7, 1 aprile 2026 | 765 | nessuna release stabile esiste | tempo della richiesta e query, esportati a un collector esterno |
xhprof |
2.0.0-beta1, 12 marzo 2025 | 205 | non coperto | costo per funzione PHP, richiede un'estensione sul server |
native_observability |
2.0.1, 21 settembre 2026 | 12 | coperto | tracce, span, metriche per rotta, cache e query, con export |
Due righe di quella tabella meritano attenzione e raramente vengono scritte. Il modulo opentelemetry, installato su 765 siti, non ha release stabili: la sua pagina dichiara «There are currently no supported stable releases». Il modulo monitoring, il più diffuso del gruppo con 2.595 siti, misura se il cron gira e se ci sono aggiornamenti, cioè la salute, che è una domanda diversa da quale rotta è lenta.
Il giudizio, separato dai dati, ed è una guida su dove andare più che un confronto. Se stai guardando la pagina mentre è lenta, apri WebProfiler: il riscontro è immediato e non devi lanciare niente. Se ti serve sapere quale funzione consuma il tempo, XHProf o Blackfire rispondono a quella domanda e Native Observability no. Se ti servono indici suggeriti sulle query lente, db_performance fa quello. Se hai più servizi e un'infrastruttura da correlare, uno stack esterno resta la scelta giusta.
Native Observability risponde a una domanda che gli altri non prendono in carico: cosa è successo a una richiesta precisa, già avvenuta, che non sai riprodurre. Ogni risposta porta un identificativo nell'header X-Native-Observability-Request-Id, e quella stringa chi ha avuto il problema può consegnartela. Da lì si arriva alla rotta, agli span e alle query lente di quella richiesta, non di una simile.
Il prezzo va detto nello stesso respiro. Si registra meno di un profiler. Ci sono soglie e tetti che buttano via dati, ed è il prezzo di restare sempre accesi. Il costo per richiesta esiste, ed è misurato invece che stimato. Non si suggeriscono indici. In cambio non serve un agente esterno, non serve un abbonamento, e i dati restano nel tuo database.
Stato del progetto
| Voce | Valore |
|---|---|
| Release stabile | 2.0.1, 21 settembre 2026 |
| Ramo corrente | 2.0.x. Il ramo 1.1.x riceve solo correzioni |
| Siti dichiarati su drupal.org | 12 |
| Issue aperte | 2, entrambe minori |
| Maintainer | Giorgio Pagano, unico |
| Copertura | security advisory policy di drupal.org |
Dodici installazioni sono poche, e le scrivo invece di ometterle. Le due issue aperte al 24 settembre 2026 riguardano un riferimento sbagliato alla versione nella documentazione di installazione e una verifica automatica di compatibilità con Drupal 12 generata da un bot: nessun bug funzionale, nessuna richiesta di supporto rimasta senza risposta.
La documentazione completa, ventisette pagine fra guida d'uso e riferimento per sviluppatori, è pubblicata su project.pages.drupalcode.org/native_observability e viene generata dal repository del modulo, quindi segue il codice invece di essere una copia che invecchia altrove.
Questo contenuto è stato prodotto dall'AI e rivisto da una persona.
Come è stata usata l'AI?
Le bozze sono prodotte con l'assistenza dell'AI, poi dirette, rivedute e verificate da una persona. Numeri, date e versioni sono confrontati con le fonti pubbliche prima della pubblicazione, e la data di quel controllo è indicata nel testo.