Become a member!

Colori Console alla Colorama (Python) e Log alla Gin (Go) in DMVCFramework

🌐
Questo articolo è disponibile anche in altre lingue:
🇬🇧 English  •  🇪🇸 Español  •  🇩🇪 Deutsch

Il ritorno della console

Le applicazioni console stanno vivendo una seconda giovinezza. Non è nostalgia: è una tendenza concreta guidata da alcuni dei trend tecnologici più rilevanti degli ultimi anni.

Gli agenti AI vivono nella console. Claude Code, GitHub Copilot CLI, Aider, Cursor Agent - gli strumenti di sviluppo assistiti da AI sono applicazioni a riga di comando. Non hanno GUI: leggono, scrivono codice e comunicano con lo sviluppatore attraverso il terminale. E lo fanno con output ricco, colorato e strutturato, perché quando l’interazione è testuale, ogni dettaglio visivo conta.

I server MCP (Model Context Protocol) sono processi console. Il protocollo MCP di Anthropic, che sta diventando lo standard per collegare AI agent a tool esterni, si basa su server che comunicano via stdin/stdout. Ogni server MCP è un’applicazione console. E con Delphi si possono scrivere server MCP nativi, veloci e con un singolo eseguibile - un vantaggio enorme rispetto agli equivalenti in Python o TypeScript che richiedono runtime e dipendenze.

I microservizi sono (spesso) applicazioni console. Docker container, servizi systemd, demoni Windows: il pattern dominante nel backend moderno è un eseguibile senza GUI che logga sulla console. I framework web moderni - da Go con Gin a Python con FastAPI e uvicorn - hanno tutti investito in log console colorati e strutturati perché è lì che lo sviluppatore passa il suo tempo durante lo sviluppo.

Le CLI tool sono ovunque. gh, docker, kubectl, terraform, npm - gli strumenti che usiamo ogni giorno sono applicazioni console con output curato. Un tool da riga di comando con output monocromatico e non strutturato sembra immediatamente datato.

In questo contesto, avere un supporto di prima classe per l’output console colorato non è un lusso: è una necessità. Ecco perché ho introdotto in DelphiMVCFramework un sistema di colori ANSI a due livelli:

  1. Primitive colorama-style (Fore, Back, Style) - costanti stringa componibili per colorare qualsiasi output console, ispirate a colorama per Python
  2. Renderer Gin-style - log HTTP strutturati e colorati, ispirati al logger di Gin per Go, attivati automaticamente in ogni applicazione DMVC

I colori console sono solo una delle tante novità in arrivo con DMVCFramework 3.5.0 “Silicon”:

  • JWT asimmetrico (RS256, PS256, ES256, EdDSA)
  • Verifica JWKS e integrazione OIDC
  • Streaming SSE e JSONL
  • Middleware RangeMedia (RFC 7233)
  • Supporto Oracle 12c+ in ActiveRecord
  • Wizard IDE completamente ridisegnato
  • Console spinner e colori ANSI
  • …e molto altro

Presenterò tutto in anteprima a ITDevCon 2026 Spring Edition. Come tutte le edizioni primaverili, la conferenza sarà interamente in italiano - un’occasione perfetta per approfondire ogni dettaglio con la community. Per chi preferisce l’edizione internazionale in inglese, l’appuntamento è a novembre con la conferenza di due giorni. Iscriviti subito!

L’API Colorama-Style: Fore, Back, Style

La unit MVCFramework.Console.pas fa parte del repository di DMVCFramework, ma non ha nessuna dipendenza dal framework. Potete copiarla e usarla in qualsiasi progetto Delphi console - un server, un tool da riga di comando, un server MCP - senza dover necessariamente includere altre dipendenze da DMVCFramework.

“La semplicità è la suprema sofisticazione” - questa frase, attribuita a Leonardo da Vinci, è il principio che ha guidato il design di questa API. Niente classi, niente oggetti, niente metodi, niente interfacce. Solo tre record con costanti stringa: Fore (colore testo), Back (colore sfondo) e Style (stile). Ogni costante è una sequenza di escape ANSI che si compone per semplice concatenazione - esattamente come colorama in Python.

Avrei potuto creare un builder pattern con method chaining, un sistema di temi con ereditarietà, un color manager thread-safe con dependency injection. Ma perché?

“La complessità va aggiunta con il bisturi, non con la pala.” — cit. Daniele Teti

Questo è un principio che ripeto spesso durante i miei corsi e che guida ogni decisione di design in DMVCFramework. Quando il problema è semplice - colorare del testo nella console - la soluzione deve essere altrettanto semplice. Se serve un’intera gerarchia di classi per scrivere una riga verde, qualcosa è andato storto.

Colori di base

program ColorBasics;
{$APPTYPE CONSOLE}
uses
  System.SysUtils, MVCFramework.Console;

begin
  EnableANSIColorConsole;

  WriteLn(Fore.Red     + 'This is red text'     + Style.ResetAll);
  WriteLn(Fore.Green   + 'This is green text'   + Style.ResetAll);
  WriteLn(Fore.Yellow  + 'This is yellow text'  + Style.ResetAll);
  WriteLn(Fore.Blue    + 'This is blue text'    + Style.ResetAll);
  WriteLn(Fore.Cyan    + 'This is cyan text'    + Style.ResetAll);
  WriteLn(Fore.Magenta + 'This is magenta text' + Style.ResetAll);
  WriteLn(Fore.White   + 'This is white text'   + Style.ResetAll);
  WriteLn(Fore.DarkGray + 'This is dark gray text' + Style.ResetAll);

  ReadLn;
end.

La funzione EnableANSIColorConsole abilita il supporto ANSI su Windows 10+ (tramite ENABLE_VIRTUAL_TERMINAL_PROCESSING). Su Linux non serve, i terminali supportano ANSI nativamente. La chiamata è idempotente: può essere invocata quante volte si vuole senza effetti collaterali.

Style.ResetAll ripristina tutti gli attributi (colore testo, sfondo e stile) ai valori predefiniti del terminale. Va sempre usato alla fine di ogni riga colorata per evitare che il colore “si propaghi” alle righe successive.

Ogni record offre 16 colori, sia nelle varianti “dark” (codici ANSI 30-37 / 40-47) che nelle varianti bright (90-97 / 100-107):

Fore/Back Dark Bright
Red DarkRed (31/41) Red (91/101)
Green DarkGreen (32/42) Green (92/102)
Yellow DarkYellow (33/43) Yellow (93/103)
Blue DarkBlue (34/44) Blue (94/104)
Magenta DarkMagenta (35/45) Magenta (95/105)
Cyan DarkCyan (36/46) Cyan (96/106)
Gray Gray (37/47) White (97/107)
Black/Gray Black (30/40) DarkGray (90/100)

Palette dei colori foreground disponibili in MVCFramework.Console

Composizione dei colori

La vera potenza dell’API è nella composizione. Essendo semplici stringhe, i colori si combinano con l’operatore +:

// Foreground + Background
WriteLn(Fore.White + Back.DarkBlue + ' White on Blue ' + Style.ResetAll);
WriteLn(Fore.Black + Back.Yellow   + ' Black on Yellow ' + Style.ResetAll);
WriteLn(Fore.White + Back.DarkRed  + ' CRITICAL ERROR ' + Style.ResetAll);

// Style + Foreground
WriteLn(Style.Bright + Fore.Green + 'Bold green text' + Style.ResetAll);
WriteLn(Style.Dim    + Fore.Cyan  + 'Dimmed cyan text' + Style.ResetAll);

// Colori inline nel testo
WriteLn(
  'Status: ' + Fore.Green + 'OK' + Style.ResetAll +
  ' | Items: ' + Fore.Cyan + '42' + Style.ResetAll +
  ' | Errors: ' + Fore.Red + '0' + Style.ResetAll
);

Non c’è nessuna classe, nessun oggetto, nessun metodo. Solo costanti stringa e concatenazione. Il compilatore risolve tutto a compile-time: zero overhead a runtime.

Composizione di colori foreground, background e stili

Badge pratici

Con Fore + Back si possono creare badge colorati per qualsiasi tipo di output strutturato:

// Test result badges
WriteLn(Back.DarkGreen + Fore.White + ' PASS ' + Style.ResetAll + '  TestUserAuth');
WriteLn(Back.DarkRed   + Fore.White + ' FAIL ' + Style.ResetAll + '  TestPaymentTimeout');
WriteLn(Back.DarkYellow + Fore.White + ' SKIP ' + Style.ResetAll + '  TestExternalAPI');

// HTTP status badges
WriteLn(Fore.White + Back.DarkGreen  + ' 200 ' + Style.ResetAll + ' GET /api/people');
WriteLn(Fore.White + Back.DarkYellow + ' 404 ' + Style.ResetAll + ' GET /api/unknown');
WriteLn(Fore.White + Back.DarkRed    + ' 500 ' + Style.ResetAll + ' GET /api/crash');

Badge pratici: test results, HTTP status e log levels

Definire stili riutilizzabili (come un CSS per la console)

Ripetere Fore.White + Back.DarkGreen ogni volta che si vuole un badge verde è verboso e fragile: se domani si decide di cambiare il verde in ciano, bisogna modificare ogni punto. La soluzione è banale ma efficace: basta definire delle costanti.

const
  STYLE_SUCCESS = Fore.White + Back.DarkGreen;
  STYLE_ERROR   = Fore.White + Back.DarkRed;
  STYLE_WARNING = Fore.White + Back.DarkYellow;
  STYLE_INFO    = Fore.White + Back.DarkBlue;
  STYLE_MUTED   = Fore.DarkGray;
  STYLE_RESET   = Style.ResetAll;

A questo punto il codice diventa pulito e leggibile, esattamente come applicare classi CSS a elementi HTML:

WriteLn(STYLE_SUCCESS + ' DONE ' + STYLE_RESET + ' Database migration completed');
WriteLn(STYLE_WARNING + ' SLOW ' + STYLE_RESET + ' Query took 3.2s on table Orders');
WriteLn(STYLE_ERROR   + ' FAIL ' + STYLE_RESET + ' Connection refused on port 5432');
WriteLn(STYLE_INFO    + ' NOTE ' + STYLE_RESET + ' Using fallback configuration');
WriteLn(STYLE_MUTED + '--- end of report ---' + STYLE_RESET);

Essendo costanti stringa risolte a compile-time, non c’è nessun overhead: il compilatore le espande inline. Si ottiene la comodità di uno stile centralizzato con le performance di stringhe hard-coded.

Log HTTP Gin-Style in DMVCFramework

La vera killer feature è il renderer TMVCColorConsoleRenderer, ispirato al logger HTTP di Gin (il popolare web framework di Go). Questo renderer è attivo di default in tutte le applicazioni DMVCFramework console - non serve configurare nulla.

Come funziona

Ogni richiesta HTTP viene loggata in formato strutturato con colori:

TIME | TID | STATUS | DURATION | IP | METHOD "path"

I badge usano gli stessi identici codici ANSI del sorgente di Gin:

Elemento Colore Codice ANSI
Status 2xx White su DarkGreen 97;42
Status 3xx DarkGray su Gray 90;47
Status 4xx White su DarkYellow 97;43
Status 5xx White su DarkRed 97;41
GET White su DarkBlue 97;44
POST White su DarkCyan 97;46
PUT White su DarkYellow 97;43
DELETE White su DarkRed 97;41
PATCH White su DarkGreen 97;42
HEAD White su DarkMagenta 97;45

Log HTTP Gin-style in un server DMVCFramework

Log level applicativi

I log non-HTTP (messaggi applicativi) usano colori distinti che non si sovrappongono con i badge HTTP:

Livello Stile Logica
DEBUG Grigio scuro Basso rumore visivo
INFO Blu Neutro, informativo
WARN Giallo Attenzione
ERROR Rosso bold Problema
FATAL Badge bianco su rosso Impossibile da ignorare

FATAL è l’unico livello applicativo con sfondo colorato: essendo il più critico, deve spiccare immediatamente anche in un log molto denso.

LogD('Processing request...');       // DEBUG - grigio, quasi invisibile
LogI('Server started on port 8080'); // INFO  - blu, informativo
LogW('Cache miss rate above 50%');   // WARN  - giallo, attenzione
LogE('Connection to database lost'); // ERROR - rosso bold, problema
Log.Fatal('Out of memory', LOGGERPRO_TAG); // FATAL - badge rosso, critico

Tutti i log level: DEBUG, INFO, WARN, ERROR, FATAL

Console colorata, file puliti

Una domanda legittima: se i log console contengono sequenze di escape ANSI, cosa succede ai log su file? La risposta è: nulla. Il sistema di logging di DMVCFramework è basato su LoggerPro, che supporta appender multipli. Ogni appender ha il proprio renderer: l’appender console usa TMVCColorConsoleRenderer che produce output colorato, mentre l’appender file usa un renderer testuale standard. I codici ANSI non finiscono mai nei file di log - ogni destinazione riceve esattamente il formato appropriato.

Fallback automatico

Il renderer console rileva automaticamente se il terminale supporta i colori ANSI. Se non li supporta (ad esempio su Windows precedente alla versione 10), produce output in testo semplice senza sequenze di escape, identico al formato precedente di DMVCFramework. Non serve nessun {$IFDEF} nel codice.

Durata delle richieste

Ogni richiesta HTTP include automaticamente il tempo di esecuzione, misurato con TStopWatch dalla System.Diagnostics. L’overhead è trascurabile (20-50 nanosecondi per chiamata) e l’informazione è preziosa per individuare endpoint lenti.

Compatibilità

Piattaforma Supporto
Windows 10+ Completo (ANSI via SetConsoleMode)
Windows < 10 Fallback testo semplice
Linux Nativo (ANSI supportato da tutti i terminali)

Provalo subito

Il codice sorgente degli esempi è disponibile nella cartella samples/console_colors* del repository GitHub:

  • samples/console_colors_basics/ - Colori di base
  • samples/console_colors_composition/ - Composizione e stili
  • samples/console_colors_badges/ - Badge pratici

Per i log Gin-style non serve fare nulla: basta creare un’applicazione DMVCFramework console e i log colorati appariranno automaticamente.

// Tutto qui. I colori sono già attivi.
program MyServer;
{$APPTYPE CONSOLE}
uses
  MVCFramework, MVCFramework.Console, MVCFramework.Logger;
begin
  // EnableANSIColorConsole è chiamata automaticamente dal renderer
  // ... il tuo server DMVC
end.

Domande frequenti

Come si aggiungono colori alla console in Delphi? Usa la unit MVCFramework.Console e i record Fore, Back, Style. Chiama EnableANSIColorConsole all’inizio del programma, poi componi i colori con la concatenazione: WriteLn(Fore.Red + 'testo rosso' + Style.ResetAll).

Funziona su Windows? Sì, su Windows 10 e successivi. La funzione EnableANSIColorConsole attiva il supporto ANSI tramite SetConsoleMode. Su versioni precedenti il renderer produce automaticamente output in testo semplice.

Posso usare i colori senza DMVCFramework? Sì. La unit MVCFramework.Console.pas non ha dipendenze dal framework. Puoi copiarla in qualsiasi progetto Delphi console.

I codici ANSI finiscono nei file di log? No. DMVCFramework usa LoggerPro con appender multipli: l’appender console usa il renderer colorato, l’appender file usa un renderer testuale standard. Ogni destinazione riceve il formato appropriato.

Qual è l’overhead del timing delle richieste? Trascurabile. TStopWatch impiega 20-50 nanosecondi per chiamata, irrilevante rispetto al tempo di elaborazione di qualsiasi richiesta HTTP.

Comments

comments powered by Disqus