Java Academy · Oppitunti

Parametrisoitu lokitus

Tehokas viestien muotoilu.

Oppitunti 3/413 vaihetta

Parametrisoitu lokitus on ilmainen Java Academy-oppitunti CoddyKitissä. Tämä on oppitunti 3/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Java Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Java Academy-kurssilla on yhteensä 4 oppituntia.

Merkkijonojen yhdistämisen ongelma

Lokiviestin yhdistäminen muodostaa koko merkkijonon ennen kutsua, vaikka taso olisi poistettu käytöstä.

log.debug("id=" + id + " name=" + name) kuluttaa suorittimen aikaa, kun DEBUG ei ole käytössä, koska merkkijono muodostetaan joka tapauksessa.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        String name = "Ada"; int id = 7;
        // Bad: string is built even if DEBUG is disabled
        log.debug("id=" + id + " name=" + name);
    }
}

Paikkamerkit muodossa {}

SLF4J käyttää {}-merkintää paikkamerkkinä. Välittäkää arvot ylimääräisinä argumentteina.

Viesti kootaan vain jos taso on käytössä, joten käytöstä poistetut lokit aiheuttavat lähes olemattoman kustannuksen.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        String name = "Ada"; int id = 7;
        // Good: no string built unless DEBUG is on
        log.debug("id={} name={}", id, name);
    }
}

Useita paikkamerkkejä

Paikkamerkit täytetään järjestyksessä. Ensimmäinen {} saa ensimmäisen argumentin, toinen toisen ja niin edelleen.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        log.info("order {} for user {} totaling {} cents", "A-1", 42, 1599);
    }
}

Miksi tämä on tehokasta

Framework tarkistaa ensin tason. Jos taso ei ole käytössä, se palaa heti kutsumatta minkään argumentin toString()-metodia.

Kallis osa eli muotoilu tehdään laiskasti vasta, kun viesti todella lähetetään.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    static String describe(Object o) { System.out.println("toString called"); return o.toString(); }
    public static void main(String[] args) {
        // Note: passing describe(...) still evaluates eagerly; pass the raw object instead
        log.trace("value={}", new int[]{1, 2, 3});
    }
}

Raakaobjektien käyttäminen valmiiksi muotoiltujen merkkijonojen sijaan

Jotta laiskasta käsittelystä saadaan hyöty, välittäkää raakaobjekti sen sijaan, että kutsuisitte sitä muotoilevaa metodia.

Jos kirjoitatte log.debug("{}", buildReport()), buildReport() suoritetaan silti heti. Välittäkää argumentit, jotka loggeri voi muotoilla itse.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        Object user = new Object();
        // Logger calls user.toString() only if DEBUG is enabled
        log.debug("current user: {}", user);
    }
}

Laiskat supplierit raskasta työtä varten

Kun muotoilu on todella kallista, käyttäkää SLF4J 2.x:n fluent APIa ja Supplier-tyyppiä työn lykkäämiseen.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    static String heavyReport() { return "...expensive..."; }
    public static void main(String[] args) {
        log.atDebug()
           .setMessage("report: {}")
           .addArgument(() -> heavyReport())
           .log();
    }
}

Kirjaimellisen aaltosulkeen merkitseminen

Jos viestissä tarvitaan kirjaimellinen {}, escapettakaa se kenoviivalla: \\{}.

Tätä tarvitaan harvoin, mutta siitä on hyötyä JSON-tyyppistä tekstiä lokitettaessa.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        // Logs a literal {} then the value
        log.info("empty object is \\{} and id is {}", 7);
    }
}

Poikkeus ja paikkamerkit

Paikkamerkkejä voi käyttää yhdessä viimeisenä annettavan poikkeuksen kanssa. SLF4J tunnistaa, että viimeinen argumentti on Throwable, ja tulostaa sen pinonjäljityksen.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        int id = 99;
        try {
            throw new RuntimeException("db down");
        } catch (Exception e) {
            log.error("failed processing record {}", id, e);
        }
    }
}

Liian monien argumenttien välttäminen

Jos paikkamerkkien ja argumenttien määrät eivät täsmää, SLF4J yrittää parhaansa, mutta tuloste voi näyttää virheelliseltä.

Huolehtikaa siitä, että määrät vastaavat toisiaan. Jos arvoja on enemmän kuin pari, harkitkaa sen sijaan rakenteisen kontekstin (MDC) käyttöä.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        // Two placeholders, two arguments: correct
        log.info("user {} did {}", "ada", "login");
    }
}

Kontekstin lisääminen MDC:llä

Jos sama arvo, kuten pyynnön tunnus, toistuu monilla riveillä, sijoittakaa se MDC:hen jokaisen viestin sijaan.

Pattern-asettelu voi silloin tulostaa MDC-arvon automaattisesti jokaiselle riville.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        MDC.put("requestId", "req-1234");
        try {
            log.info("handling request");
            log.info("request done");
        } finally {
            MDC.clear();
        }
    }
}

Parhaiden käytäntöjen yhteenveto

Tehokkaan lokituksen säännöt:

  • Käyttäkää aina {}-paikkamerkkejä, älkää koskaan +-merkkijonojen yhdistämistä.
  • Välittäkää raakaobjekteja, älkää valmiiksi muodostettuja merkkijonoja.
  • Käyttäkää suppliereita tai isXEnabled()-metodia todella raskasta työtä varten.
  • Käyttäkää MDC:tä poikittaisen kontekstin välittämiseen.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        log.info("processed {} items in {} ms", 1000, 42);
    }
}

Pikatarkistus

Testatkaa parametrisoidun lokituksen tuntemustanne.

Kertaus

Opitte parametrisoidun lokituksen:

  • Käyttäkää {}-paikkamerkkejä ylimääräisten argumenttien kanssa.
  • Viestit muodostetaan laiskasti vain, kun taso on käytössä.
  • Välittäkää raakaobjekteja ja käyttäkää suppliereita raskasta työtä varten.
  • Käyttäkää MDC:tä jaettujen kontekstiarvojen välittämiseen.

Seuraavaksi määritetään Logback-backend.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        log.info("Parameterized logging recap: {}", "done");
    }
}
Aloita maksutta

Opi Java tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
104
Oppitunnit
374

Usein kysytyt kysymykset

Onko oppitunti ”Parametrisoitu lokitus” ilmainen?

Kyllä – oppitunnin ”Parametrisoitu lokitus” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Java Academy-kurssin, päivitä CoddyKit PROhon. Java Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Parametrisoitu lokitus”?

Tehokas viestien muotoilu. Harjoittelet Java Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Java Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Java Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 3/4.

Kuinka kauan ”Parametrisoitu lokitus”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Java Academy-oppitunnilla?

Kyllä. Jokainen Java Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Miksi rakenteinen lokitus
  2. SLF4J-julkisivu ja lokittimet
  3. Parametrisoitu lokitus
  4. Logbackin määrittäminen
← Takaisin: Java Academy