Bygg en Logger Mixin i Sass

I denne opplæringen bygger vi en "logger" mixin, som utgir en fleksibel, informativ logg som CSS når Sass er kompilert.

Logging er prosessen med å registrere programhandlinger og angi til et sekundært grensesnitt. - Kode Prosjekt

Ideen

Den andre dagen, snakkes opprettholder Reda Lemedan og jeg snakket alle ting Sass og plutselig så jeg en interessant blanding av hans:

@include-nei-advarsel ("noe er galt"); 

Jeg spurte ham hva denne blandingen gjør, og han fortalte meg at det egentlig er en wrapper for @varsle Direktiv fra Sass som sjekker om brukeren er villig til å skrive ut advarsler fra Neat i konsollen (basert på en global variabel).

Så tenkte jeg på meg selv hvorfor stoppe der? og begynte å spille med ideen samme natt. Min ide var å bygge en wrapper for begge @varsle og @feil (fra Sass 3.4) for å hjelpe bibliotek og rammeverkutviklere skrive ut forskjellige typer meldinger (info, feilsøking, advarsel, feil ...) og følg alle loggene.

Min nåværende implementering gir:

  • 5 nivåer av logging (DEBUG, INFO, VARSLE, FEIL og FATAL);
  • et minimumsnivå der loggeren starter utskrift
  • en historie med alle loggene, som kan skrives ut som CSS;
  • en vennlig API med brukervennlige funksjoner;
  • en hjelper til å lære mer om ulike nivåer av logging.

Hvordan virker det?

Det viste seg å være ganske grei. Vi trenger en global variabel som holder hele konfigurasjonen, og en mixin som fungerer som en wrapper for våre konsolutskriftsdirektiver.

Fordi vi ønsker at vår globale konfigurasjon kan tilpasses (til en viss grad), pakker vi inn erklæringen i en mixin. Ikke bare er dette mer praktisk, men det er også bedre for sluttbrukeren.

Så vi har en mixin, la oss kalle det logger Det er bare ment å bli kalt en gang, og skape et globalt kart som holder vår konfigurasjon. Da har vi vår wrapper, Logg, som aksepterer et loggnivå (for eksempel VARSLE eller FEIL) og meldingen til å logge som argumenter. Det er ganske mye det.

For å gjøre ting mer praktisk for utviklerne, vil vi gi noen kortfunksjoner for å logge forskjellige nivåer. For eksempel, i stedet for å skrive:

@include log ("ERROR", "Det er ikke nok enhjørning her."); 

... vi kunne ha:

@include ERROR ("Det er ikke nok enhjørning her."); 

Så du vil ende opp med en API som ser slik ut:

// Instantiate a logger // som starter utskriftslogger på 'INFO'-nivå. // Dette betyr at "DEBUG" logger ikke vil bli vist. @include logger ("INFO"); // Logg ting. @include ERROR ("Det er ikke nok enhjørning her."); 

Vi vil også legge til noen mikser for å få inn noen kule ekstrafunksjoner:

  • en utskriftsinformasjon om hvert loggnivå som en påminnelse;
  • en skriver ut alle loggene som er registrert i den nåværende samlingen.

Bygg API

Logger Constructor

La oss begynne med begynnelsen, skal vi? Loggeren konstruktør. Dette bør akseptere en enkelt parameter: nivået der loggeren skal begynne å skrive ut logger i konsollen.

Dette er ganske vanlig for loggingssystemer. For eksempel:

  • Hvis du bare vil skrive ut feil (FEIL og FATAL), ville du skrive @include logger ("ERROR").
  • Hvis du vil skrive ut alt, vil du gå med @include logger ("ALL"), som i utgangspunktet er det samme som det laveste loggnivået (DEBUG).
  • Hvis du vil deaktivere loggeren helt, kjører du @include logger ("OFF").

Merk: Du finner mer informasjon om loggnivåer i denne StackOverflow-tråden eller i Apache-loggdokumentasjonen.

@mixin logger ($ minimum nivå) // Liste over tilgjengelige nivåer $ nivåer: "DEBUG", "INFO", "WARN", "ERROR", "FATAL"; // Sørg for at den oppgitte strengen er stort sett $ minimumsnivå: til-øvre tilfelle ($ minimumsnivå); // Hvis nivået er 'ALL', gå med laveste nivå på alle @if $ minimumsnivå == "ALL" $ minimumsnivå: nth ($ nivåer, 1);  // Hvis nivået er ugyldig, går det med "INFO" @if ikke indeks ($ nivåer "AV", minimumsnivå) $ minimumnivå: "INFO";  // Opprett global variabel $ logger-konfigurasjon: (// Liste over tilgjengelige nivåer "nivåer": $ nivåer, // Liste over nivåer som er skrevet med '@error' "feil": "FATAL" "FEIL", / / Minimumsnivå (som en indeks på '$ nivåer') for å skrive ut "min": indeks ($ nivåer, $ minimumsnivå), // Om loggeren er aktivert "aktivert": $ minimumnivå! = " OFF ", // Et kart for å holde oversikt over alle loggene" historie ": (" DEBUG ": ()," INFO ": ()," WARN ": ()," ERROR ": ()," FATAL " ()))! global;  

Koden ovenfor skal for det meste være selvforklarende, men jeg har lagt til noen kommentarer for å gjøre alt klart. Som du kan se, gjør denne mixin ikke mye, med unntak av å opprette en global variabel. Ikke så ille, er det?

Før vi går videre, la oss lage en liten hjelperfunksjon som gjør det enkelt for oss å få en verdi fra dette globale kartet. Fordi du vet, skriver du map-get ($ logger-konfigurasjon, ...) er ikke ekstremt morsomt. Hva med logger-conf (...) i stedet?

@function logger-conf ($ key) @return map-get ($ logger-konfigurasjon, $ key);  

Log Wrapper

Ok, la oss gå videre til selve Logg funksjon som skriver ut ting i konsollen. Ikke bare bør det sende ut de oppgitte meldingene i brukerens konsoll, men det bør også oppdatere historien for å holde oversikt over hva som blir logget (som kanskje eller kanskje ikke er nyttig).

Det høres vanskelig ut. Vel bekymre ikke, det kommer til å bli så glatt som smør. Vi vet allerede at denne mixin skal akseptere bare to parametre: loggnivået og meldingen.

@mixin logg ($ nivå, $ melding) // Kontroller at nivået er stort sett $ nivå: til-øvre tilfelle ($ nivå); // Hvis ikke det er deaktivert, fortsett @if logger-conf ("enabled") // Få indeksen for nåværende nivå // For eksempel vil DEBUG være '1' $ indeks-nåværende nivå: indeks (logger-conf "nivåer"), $ nivå); // Hvis '$ level' er ugyldig, // vilkårlig faller tilbake på 'INFO' @if ikke $ index-nåværende nivå $ level: "INFO";  // Oppdater loggerhistorikk @ inkluder loggeroppdateringshistorikk ($ nivå, $ melding); // Endelig, skriv ut meldingen i konsollen // hvis nåværende nivå er større enn eller lik minimumsnivå. @if $ indeks-nåværende nivå> = logger-conf ("min") $ print: '[' + $ level + '] ::' + $ message; // Skriv det som '@error' hvis det er et feilnivå @if index (logger-conf ("feil"), $ nivå) @error $ print;  // Else bruk '@warn' @else @warn $ print;  

Nå må vi håndtere historien. Dette er faktisk litt tøffere, men når du blir vant til kartmanipulering, blir det klarere.

Før jeg ser på koden, la meg forklare hvordan historien fungerer. I utgangspunktet er det et kart hvor nøkler er loggnivåene, og verdier er lister over loggede meldinger. For eksempel kan du ha noe som:

$ _: ("DEBUG": (), "INFO": (), "WARN": ("Du bør være oppmerksom på dette.", "Dette kan forbedres."), "FEIL": ." ), "FATAL": () ) 

Greit. La oss gå.

@mixin logger-update-history ($ nivå, $ message) // Få historikk kart fra konfigurasjon $ history: logger-conf ("history"); // Få historikkliste for nåværende nivå $ nåværende nivåhistorikk: map-get ($ history, $ level); // Legg den nye loggen til listen $ nåværende nivåhistorikk: legg til ($ nåværende nivåhistorie, $ melding); // Opprett en midlertidig variabel som inneholder det nye historikkarket $ loggerhistorikk: kartfelt ($ historie, ($ nivå: $ nåværende nivåhistorie)); // Oppdater historikk kartet fra konfigurasjonen med vår midlertidige variabel $ logger-konfigurasjon: kart-flette ($ logger-konfigurasjon, ("historie": $ logger-historie))! Global;  

Det innebærer ganske mange uvanlige linjer, men når du forklarer hver linje hver for seg, er det helt sikkert fornuftig.

Vi er ferdige her, men vi snakket om å legge til shorthandfunksjoner. La oss gjøre det nå før vi glemmer:

@mixin FATAL ($ message) @include logg ("FATAL", $ melding);  @mixin FEIL ($ melding) @include log ("ERROR", $ message);  @mixin WARN ($ message) @include log ("WARN", $ message);  @mixin INFO ($ melding) @include log ("INFO", $ message);  @mixin DEBUG ($ melding) @include log ("DEBUG", $ melding);  

Det er det. En siste ting vi kunne gjøre, men egentlig ikke er obligatorisk, tester om logger har blitt inkludert før du prøver å bruke det globale kartet. Ikke bare forhindrer vi dumme feil, men vi kan også gjøre loggeroppsigelsen valgfri ved å gjøre det på fluen.

@mixin logg ($ level, $ message) // Test om global loggerkonfigurasjon er tilgjengelig. // Hvis det ikke betyr det, betyr det at "logger" ikke er inkludert, // så vi inkluderer det, vilkårlig sette min nivå til 'INFO'. @if ikke global variabel-eksisterer ("logger-konfigurasjon") @include logger ("INFO");  @if logger-conf ("aktivert") // ... 

Legge til tillegg

Vi starter med den første (og minst nyttige) av begge ekstra mixins, hjelperen. Det er virkelig en gadget på dette punktet, siden alt det gjør er å skrive ut en CSS-regel med logging nivåer som selektorer, og forklaringer som verdier.

Dette har til hensikt å gi noen hjelp til utviklere når de ikke vet hva loggnivå de skal bruke. Det kunne ha blitt skrevet som en kommentar, men jeg ville prøve denne hjelpeskriveren dingie.

@mixin logger-help // Åpne en ny logger-help-selger logger-hjelp OFF: "Deaktiver loggeren."; FATAL: "Alvorlige feil som forårsaker for tidlig avslutning."; FEIL: "Andre kjøretidsfeil eller uventede forhold."; WARN: "Bruk av utdaterte APIer, dårlig bruk av API," nesten "feil," + "andre runtime situasjoner som er uønskede eller uventede, men ikke nødvendigvis feil."; INFO: "Interessante runtime hendelser (oppstart / avslutning)."; DEBUG: "Detaljert informasjon om strømmen gjennom systemet.";  

Du bruker det slik:

@include logger-hjelp; 

... og det kompilerer som:

logger-hjelp OFF: "Deaktiver loggeren."; FATAL: "Alvorlige feil som forårsaker for tidlig avslutning."; FEIL: "Andre kjøretidsfeil eller uventede forhold."; WARN: "Bruk av utdaterte APIer, dårlig bruk av API," nesten "feil, andre runtime situasjoner som er uønskede eller uventede, men ikke nødvendigvis feil."; INFO: "Interessante runtime hendelser (oppstart / avslutning)."; DEBUG: "Detaljert informasjon om strømmen gjennom systemet."; 

Ikke noe spesielt. Den andre ekstra mixin er langt mer interessant. Det bruker historien til å skrive ut alle loggene som er registrert under samlingen.

@mixin logger-print-logs // Åpne en ny loggerlogger 'loggerlogger // Gå over historien @each $ level, $ logger i logger-conf ("history") // Sjekk om Nåværende loggnivå fra loop // skal vises eller ikke basert på minimumsnivå // og lengden på verdien (ingen logg, ingen utskrift). @if-indeks (logger-conf ("nivåer"), $ nivå)> = logger-conf ("min") og lengde ($ logger)> 0 // Gå over de registrerte loggene og skriv ut dem. @ $ $ logg inn $ logger # $ level: $ log;  

Igjen, enkel bruk:

@include logger-print-logger; 

... som ville produsere (basert på vårt tidligere eksempel):

loggerlogger WARN: "Du bør være oppmerksom på dette."; ADVARSEL: "Dette kan forbedres."; FEIL: "Noe er ødelagt";  

Eksempel

// Instant en ny logger med 'INFO' som minimumsnivå for logging. // Hvis ikke inkludert, vil det automatisk bli gjort på første logg. @include logger ("INFO"); // Logger hjelp (valgfritt, selvsagt) @ include logger-help; // Logg ting @include INFO ("Hei, se på det."); @include INFO ("Ta med enhjørningene!"); @include WARN ("Dude, vær oppmerksom."); // Denne er ikke skrevet ut, men spores fortsatt i logger. @include DEBUG ("Debug and stuff."); // Utgangshistorikk (valgfritt) spesielt nyttig for feilsøking @ inkludere logger-utskriftslogger; 

Siste tanker

Som du ser, er koden ganske lett i slutten, pluss det meste av massen er kommentarer. Jeg tror det gir en fin, ren API som hjelper til med å holde oversikt over hva som blir logget inn i et gitt prosjekt.

Dette er verktøy rettet mot bibliotek og rammeverk utviklere. Hvis du er en, vennligst gi dette en prøve hvis du tror det kan være nyttig, og gi meg din tilbakemelding.

Ta gjerne mixin fra GitHub, eller spill med den direkte på SassMeister.