Por que não usar java.util.logging?


351

Pela primeira vez na minha vida, me encontro em uma posição em que estou escrevendo uma API Java que será de código aberto. Espero que seja incluído em muitos outros projetos.

Para o registro, eu (e de fato as pessoas com quem trabalho) sempre usei o JUL (java.util.logging) e nunca tive problemas com ele. No entanto, agora eu preciso entender com mais detalhes o que devo fazer para o desenvolvimento da minha API. Eu fiz algumas pesquisas sobre isso e com as informações que tenho, fico mais confuso. Daí este post.

Desde que eu venho de JUL, estou inclinado a isso. Meu conhecimento do resto não é tão grande.

A partir da pesquisa que fiz, descobri estas razões pelas quais as pessoas não gostam do JUL:

  1. "Comecei a desenvolver em Java muito antes da Sun lançar o JUL e era mais fácil continuar com o logging-framework-X do que aprender algo novo" . Hmm. Não estou brincando, é isso que as pessoas dizem. Com esse argumento, todos nós poderíamos estar fazendo COBOL. (no entanto, eu certamente posso me relacionar com esse ser um cara preguiçoso)

  2. "Não gosto dos nomes dos níveis de registro em JUL" . Ok, sério, isso não é motivo suficiente para introduzir uma nova dependência.

  3. "Não gosto do formato padrão da saída de JUL" . Hmm. Isso é apenas configuração. Você nem precisa fazer nada em termos de código. (verdade, nos velhos tempos, você pode ter que criar sua própria classe Formatter para fazer a coisa certa).

  4. "Eu uso outras bibliotecas que também usam o logging-framework-X, então achei mais fácil usar essa" . Este é um argumento circular, não é? Por que 'todo mundo' usa o logging-framework-X e não o JUL?

  5. "Todo mundo está usando o logging-framework-X" . Isso para mim é apenas um caso especial do exposto acima. A maioria nem sempre está certa.

Então a grande questão é: por que não JUL? . Do que sinto falta? A razão de ser das fachadas de log (SLF4J, JCL) é que várias implementações de log existem historicamente e a razão disso realmente remonta à era anterior a JUL, como eu a vejo. Se JUL fosse perfeito, as fachadas de madeira não existiriam, ou o quê? Para tornar as coisas mais confusas, o JUL é, de certa forma, uma fachada, permitindo que os manipuladores, formatadores e até o LogManager sejam trocados.

Em vez de adotar várias maneiras de fazer a mesma coisa (registro), não deveríamos questionar por que elas eram necessárias em primeiro lugar? (e veja se esses motivos ainda existem)

Ok, minha pesquisa até agora levou a algumas coisas que eu posso ver que podem ser problemas reais com JUL:

  1. Desempenho . Alguns dizem que o desempenho no SLF4J é superior ao resto. Parece-me um caso de otimização prematura. Se você precisar registrar centenas de megabytes por segundo, não tenho certeza se você está no caminho certo. O JUL também evoluiu e os testes que você fez no Java 1.4 podem não ser mais verdadeiros. Você pode ler sobre isso aqui e esta correção chegou ao Java 7. Muitos também falam sobre a sobrecarga da concatenação de strings nos métodos de log. No entanto, o log baseado em modelo evita esse custo e ele também existe em JUL. Pessoalmente, eu nunca escrevo logs baseados em modelos. Com preguiça de fazer isso. Por exemplo, se eu fizer isso com JUL:

    log.finest("Lookup request from username=" + username 
       + ", valueX=" + valueX
       + ", valueY=" + valueY));

    meu IDE me avisará e pedirá permissão para alterá-lo para:

    log.log(Level.FINEST, "Lookup request from username={0}, valueX={1}, valueY={2}", 
       new Object[]{username, valueX, valueY});

    .. o que eu obviamente aceitarei. Permissão garantida ! Obrigado pela ajuda.

    Então, eu realmente não escrevo essas declarações pessoalmente, isso é feito pelo IDE.

    Concluindo sobre a questão do desempenho, não encontrei nada que sugerisse que o desempenho do JUL não seja bom em comparação com a concorrência.

  2. Configuração do caminho de classe . O JUL pronto para o uso não pode carregar um arquivo de configuração do caminho de classe. São algumas linhas de código para fazê-lo. Eu posso ver por que isso pode ser irritante, mas a solução é curta e simples.

  3. Disponibilidade de manipuladores de saída . O JUL vem com 5 manipuladores de saída prontos para uso: console, fluxo de arquivos, soquete e memória. Estes podem ser estendidos ou novos podem ser escritos. Por exemplo, isso pode estar gravando no Syslog do UNIX / Linux e no Log de Eventos do Windows. Pessoalmente, nunca tive esse requisito nem o vi usado, mas certamente posso me relacionar com o porquê de ser um recurso útil. O Logback vem com um aplicativo para o Syslog, por exemplo. Ainda assim, eu argumentaria que

    1. 99,5% das necessidades de destinos de saída são cobertas pelo que está em JUL pronto para uso.
    2. Necessidades especiais podem ser atendidas por manipuladores personalizados em cima de JUL em vez de em cima de outra coisa. Não há nada que sugira que demore mais tempo para escrever um manipulador de saída Syslog para JUL do que para outra estrutura de log.

Estou realmente preocupado que haja algo que eu tenha esquecido. O uso de fachadas de log e implementações de log diferentes de JUL é tão difundido que tenho que chegar à conclusão de que sou eu quem simplesmente não entende. Receio que não seja a primeira vez. :-)

Então, o que devo fazer com a minha API? Eu quero que seja bem sucedido. É claro que posso simplesmente "seguir o fluxo" e implementar o SLF4J (que parece o mais popular hoje em dia), mas, por mim mesmo, ainda preciso entender exatamente o que há de errado com o JUL de hoje que justifica toda essa confusão. Vou me sabotar escolhendo JUL para minha biblioteca?

Teste de desempenho

(seção adicionada por nolan600 em 07-JUL-2012)

Há uma referência abaixo de Ceki sobre a parametrização do SLF4J ser 10 vezes ou mais rápida que a JUL. Então eu comecei a fazer alguns testes simples. À primeira vista, a afirmação está certamente correta. Aqui estão os resultados preliminares (mas continue a ler!):

  • Tempo de execução SLF4J, back-end Logback: 1515
  • Tempo de execução SLF4J, back-end JUL: 12938
  • Tempo de execução JUL: 16911

Os números acima são ms, portanto menos é melhor. Então, 10 vezes a diferença de desempenho é, na verdade, bem próxima. Minha reação inicial: Isso é muito!

Aqui está o núcleo do teste. Como pode ser visto, um número inteiro e uma string são construídos em um loop, que é usado na instrução de log:

    for (int i = 0; i < noOfExecutions; i++) {
        for (char x=32; x<88; x++) {
            String someString = Character.toString(x);
            // here we log 
        }
    }

(Eu queria que a instrução de log tivesse um tipo de dados primitivo (neste caso, um int) e um tipo de dados mais complexo (nesse caso, uma String). Não tenho certeza se isso importa, mas você o possui.)

A instrução de log para SLF4J:

logger.info("Logging {} and {} ", i, someString);

A instrução de log para JUL:

logger.log(Level.INFO, "Logging {0} and {1}", new Object[]{i, someString});

A JVM foi 'aquecida' com o mesmo teste executado uma vez antes da medição real ter sido feita. O Java 1.7.03 foi usado no Windows 7. As versões mais recentes do SLF4J (v1.6.6) e Logback (v1.0.6) foram usadas. Stdout e stderr foram redirecionados para o dispositivo nulo.

No entanto, com cuidado agora, verifica-se que JUL está gastando a maior parte do tempo getSourceClassName()porque JUL, por padrão, imprime o nome da classe de origem na saída, enquanto o Logback não. Então, estamos comparando maçãs e laranjas. Eu tenho que fazer o teste novamente e configurar as implementações de log de maneira semelhante para que elas realmente produzam as mesmas coisas. No entanto, desconfio que o SLF4J + Logback ainda esteja no topo, mas longe dos números iniciais, como indicado acima. Fique ligado.

Btw: O teste foi a primeira vez que trabalhei com SLF4J ou Logback. Uma experiência agradável. JUL é certamente muito menos acolhedor quando você está começando.

Testando o desempenho (parte 2)

(seção adicionada por nolan600 em 08-JUL-2012)

Como se vê, não importa muito para o desempenho como você configura seu padrão em JUL, ou seja, se inclui ou não o nome da fonte. Eu tentei com um padrão muito simples:

java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"

e isso não mudou os horários acima. Meu criador de perfil revelou que o criador de logs ainda passava muito tempo em chamadas, getSourceClassName()mesmo que isso não fizesse parte do meu padrão. O padrão não importa.

Portanto, estou concluindo sobre a questão do desempenho que, pelo menos para a declaração de log baseada em modelo testada, parece haver um fator de aproximadamente 10 na diferença real de desempenho entre JUL (lento) e SLF4J + Logback (rápido). Assim como Ceki disse.

Também posso ver outra coisa, a saber, que a getLogger()ligação do SLF4J é muito mais cara que a da JUL. (95 ms vs 0,3 ms se meu criador de perfil for preciso). Isso faz sentido. O SLF4J precisa dedicar algum tempo à ligação da implementação de log subjacente. Isso não me assusta. Essas chamadas devem ser um pouco raras durante a vida útil de um aplicativo. A rapidez deve estar nas chamadas de log reais.

Conclusão final

(seção adicionada por nolan600 em 08-JUL-2012)

Obrigado por todas as suas respostas. Ao contrário do que pensei inicialmente, decidi usar o SLF4J para minha API. Isso é baseado em várias coisas e na sua entrada:

  1. Ele oferece flexibilidade para escolher a implementação do log no momento da implantação.

  2. Problemas com falta de flexibilidade da configuração do JUL quando executados dentro de um servidor de aplicativos.

  3. O SLF4J é certamente muito mais rápido, conforme detalhado acima, principalmente se você o associar ao Logback. Mesmo que este fosse apenas um teste aproximado, tenho motivos para acreditar que muito mais esforço foi feito na otimização no SLF4J + Logback do que no JUL.

  4. Documentação. A documentação do SLF4J é simplesmente muito mais abrangente e precisa.

  5. Flexibilidade de padrões. Ao fazer os testes, decidi imitar JUL o padrão padrão do Logback. Esse padrão inclui o nome do encadeamento. Acontece que o JUL não pode fazer isso imediatamente. Ok, não perdi até agora, mas acho que não deve faltar em uma estrutura de log. Período!

  6. Muitos (ou muitos) projetos Java hoje usam o Maven, portanto, adicionar uma dependência não é algo tão importante, especialmente se essa dependência é bastante estável, ou seja, não muda constantemente sua API. Isso parece ser verdade para o SLF4J. Além disso, o frasco e os amigos do SLF4J são pequenos.

Então o estranho que aconteceu foi que eu fiquei bastante chateado com o JUL depois de trabalhar um pouco com o SLF4J. Ainda me arrependo de que tenha sido assim com JUL. JUL está longe de ser perfeito, mas meio que faz o trabalho. Apenas não muito bem o suficiente. O mesmo pode ser dito Propertiescomo exemplo, mas não pensamos em abstrair que as pessoas possam conectar sua própria biblioteca de configuração e o que você possui. Eu acho que a razão é que Propertiesaparece logo acima da barra, enquanto o oposto é verdadeiro para JUL de hoje ... e no passado ele chegou a zero porque não existia.


8
Não vou fazer um fechamento, pois essa pergunta bem apresentada é interessante, mas é limítrofe se você ler o FAQ: será difícil encontrar uma resposta única e definitiva, não baseada em opiniões.
Denys Séguret

O que você pode ter perdido é que muitos autores de framework desistiram de tentar usar o JUL e, portanto, muitas vezes é mais difícil usá-lo se você simplesmente não cria vanilla java.
Denys Séguret

3
É enganoso usar o termo genérico "logging-framework-X" quando se refere a estruturas populares de log anteriores a jul. Você deve usar "log4j" neste caso. Outras estruturas populares, como SLF4J e logback, vieram bem após o lançamento de julho.
Ceki

11
@Acuariano. O projeto Netty está simplesmente usando o Reflection para testar qual estrutura de log está disponível no caminho de classe. Veja aqui a fonte. Veja InternalLoggerFactory.java.
Peterh

11
O @xenoterracide ainda mais importante seria uma atualização para o Java 9, que foi introduzida java.lang.System.Logger, que é uma interface que pode ser redirecionada para qualquer estrutura de log real que você desejar, desde que essa estrutura seja atualizada e forneça uma implementação dessa interface. Combinado com a modularização, você pode até implementar um aplicativo com um JRE em pacote que não contenha java.util.logging, se preferir uma estrutura diferente.
Holger

Respostas:


207

Isenção de responsabilidade : Eu sou o fundador dos projetos log4j, SLF4J e logback.

Existem razões objetivas para preferir o SLF4J. Por um lado, o SLF4J permite ao usuário final a liberdade de escolher a estrutura de log subjacente . Além disso, os usuários mais experientes tendem a preferir o logback, que oferece recursos além do log4j , com julho ficando para trás. O jul em termos de recursos pode ser suficiente para alguns usuários, mas para muitos outros simplesmente não é. Em poucas palavras, se o registro for importante para você, você poderá usar o SLF4J com o logback como a implementação subjacente. Se o registro não for importante, jul está bem.

No entanto, como desenvolvedor de sistemas operacionais, você precisa levar em consideração as preferências de seus usuários e não apenas as suas. Segue-se que você deve adotar SLF4J não porque você está convencido de que SLF4J é melhor do que julho, mas porque a maioria dos desenvolvedores Java atualmente (Julho de 2012) preferem SLF4J como sua API de registro. Se, em última análise, você decidir não se importar com a opinião popular, considere os seguintes fatos:

  1. aqueles que preferem jul o fazem por conveniência, porque jul é fornecido com o JDK. Que eu saiba, não há outros argumentos objetivos a favor de jul
  2. sua própria preferência por jul é apenas isso, uma preferência .

Assim, manter "fatos concretos" acima da opinião pública, embora aparentemente corajoso, é uma falácia lógica nesse caso.

Se ainda não estiver convencido, JB Nizet apresenta um argumento adicional e potente:

Exceto que o usuário final já poderia ter feito essa customização para seu próprio código ou outra biblioteca que usa log4j ou logback. jul é extensível, mas ter que estender o logback, jul, log4j e só Deus sabe qual outra estrutura de log, porque ele usa quatro bibliotecas que usam quatro estruturas de log diferentes é complicado. Ao usar o SLF4J, você permite que ele configure as estruturas de log que ele deseja, e não a que você escolheu. Lembre-se de que um projeto típico usa inúmeras bibliotecas, e não apenas a sua .

Se, por qualquer motivo, você detestar a API do SLF4J e utilizá-la, acabará com a diversão de seu trabalho, e, por todos os meios, julgue . Afinal, existem maneiras de redirecionar jul para o SLF4J .

A propósito, a parametrização de julho é pelo menos 10 vezes mais lenta que o SLF4J, o que acaba fazendo uma diferença notável.


2
@ Cecki, você pode elaborar um pouco o seu aviso de isenção de responsabilidade, para que ele mencione sua função atual nos projetos log4j, slf4j e logback. O motivo é, naturalmente, explicar o seu preconceito.
Thorbjørn Ravn Andersen

2
Existe algum suporte para a alegação de que a maioria dos desenvolvedores Java prefere o SLF4J como sua API de log?
Olivier Cailloux 01/03

3
A essência do meu post é que diferentes desenvolvedores têm preferências diferentes, o que parece inquestionável. Sim?
Ceki

11
sinceramente, eu adoraria ver os benchmarks de 2018 no Java 11 (ou o que quer que isso acabe sendo) e contra o log4j2 no modo assíncrono.
Xenoterracide

5
Aqui estou, usando o SLF4J, e ainda preciso lidar com todas as outras estruturas de log que outras bibliotecas usam. O uso do SLF4J não resolve o problema de registradores heterogêneos, apenas o torna pior. xkcd.com/927
Charlie

34
  1. java.util.loggingfoi introduzido no Java 1.4. Antes, havia usos para o log, é por isso que existem muitas outras APIs de log. Essas APIs eram usadas muito antes do Java 1.4 e, portanto, tinham uma grande participação no mercado que não caiu para 0 quando o 1.4 foi lançado.

  2. O JUL não começou muito bem, muitas das coisas que você mencionou foram muito piores no 1.4 e só melhoraram no 1.5 (e acho que no 6 também, mas não tenho muita certeza).

  3. O JUL não é adequado para vários aplicativos com configurações diferentes na mesma JVM (pense em vários aplicativos da web que não devem interagir). O Tomcat precisa passar por alguns obstáculos para fazê-lo funcionar (efetivamente reimplementando o JUL, se eu entendi direito).

  4. Você nem sempre pode influenciar qual estrutura de log suas bibliotecas usam. Portanto, o uso do SLF4J (que na verdade é apenas uma camada de API muito fina acima de outras bibliotecas) ajuda a manter uma imagem um pouco consistente de todo o mundo do log (para que você possa decidir a estrutura de log subjacente enquanto ainda mantém o log da biblioteca no mesmo sistema).

  5. Bibliotecas não podem mudar facilmente. Se uma versão anterior de uma biblioteca costumava usar a biblioteca de log-X, ela não pode facilmente mudar para a biblioteca de log-Y (por exemplo, JUL), mesmo que a última seja claramente superiosa: qualquer usuário dessa biblioteca precisaria aprender a nova estrutura de log e (pelo menos) reconfigure seu log. É um grande não-não, especialmente quando não traz ganho aparente para a maioria das pessoas.

Dito tudo isso, acho que o JUL é pelo menos uma alternativa válida para outras estruturas de registro atualmente.


11
Obrigado Joachim, agradeço o seu post. O seu (1) e (2) são para mim apenas história. Há muito tempo. O seu (4) é uma consequência disso e então se torna o que chamo de argumento cíclico. Seu (3) é, no entanto, realmente interessante. Talvez você esteja interessado em alguma coisa? Mas isso afetaria apenas aqueles que estão construindo contêineres de aplicativos que, no final do dia, são muito poucas pessoas. Ou o que?
Peterh

3
Bem, quem ignora a história está fadado a repeti-la ;-) A história é muito relevante no desenvolvimento de software. As pessoas não se movem muito rápido e a substituição de bibliotecas de terceiros existentes por APIs padrão funciona bem se as APIs padrão funcionarem pelo menos tão bem quanto as bibliotecas de terceiros. E eles não o fizeram inicialmente (e provavelmente ainda não o fazem em alguns casos).
Joachim Sauer

Joachim, estou interessado naqueles "indiscutivelmente ainda não em alguns casos" que você mencionou. É onde a carne tem que ser. Substituir uma biblioteca de criadores de logs em seu código existente é bastante trivial e pode ser automatizado atualmente. O SLF4J tem uma ferramenta para aquilo que prova meu ponto de vista. Então, eu pensaria que uma enorme biblioteca escrita em 2002 com o log4j poderia ser convertida para JUL em questão de minutos com uma ferramenta automatizada. (Eu não sei se existe, no entanto). Então, por que isso não acontece?
Peterh

3
@ nolan6000: Eu não sei o suficiente sobre os detalhes para entrar em detalhes sobre essa frase, e não é exatamente isso que estou fazendo. Mesmo que o JUL esteja agora em pé de igualdade com estruturas de terceiros, a inércia e a infraestrutura existente ainda são um forte motivo para não mudar. Por exemplo, se a biblioteca X usasse slf4j na versão 1.1, alternar para JUL na versão 1.2 (ou mesmo 2.0) seria um grande problema para muitos usuários (que já configuraram corretamente o sistema antigo e precisariam refazê-lo sem nenhum ganho aparente) .
Joachim Sauer

@ nolan6000 mesmo que você não se importe com o histórico, as bibliotecas que você usa nos seus aplicativos certamente o fazem. Não é divertido ter que descartar uma biblioteca simplesmente porque ela usa uma estrutura de log diferente da sua.
Thorbjørn Ravn Andersen

29

IMHO, a principal vantagem do uso de uma fachada de registro como o slf4j é que você permite que o usuário final da biblioteca escolha qual implementação de registro concreto ele deseja, em vez de impor sua escolha ao usuário final.

Talvez ele tenha investido tempo e dinheiro no Log4j ou LogBack (formatadores especiais, anexadores, etc.) e prefere continuar usando o Log4j ou o LogBack, em vez de configurar jul. Não tem problema: o slf4j permite isso. É uma escolha sábia usar o Log4j em julho? Talvez talvez não. Mas você não se importa. Deixe o usuário final escolher o que ele prefere.


Obrigado JB. Minha pergunta é se estou realmente impondo tanto ao usuário / implementador da minha biblioteca forçando JUL a ele? Se ele não estiver satisfeito com, por exemplo, os manipuladores de saída padrão da JUL, ele pode trocá-los pelos seus no momento da implantação, como eu vejo. Eu realmente não vejo JUL como uma camisa de força. Parece-me tão flexível e extensível quanto o resto deles.
Peterh

12
Exceto que o usuário final já poderia ter feito essa personalização para seu próprio código ou para outra biblioteca que usa log4j ou LogBack. jul é extensível, mas ter que estender o LogBack, jul, log4j e só Deus sabe qual outra estrutura de log, porque ele usa 4 bibliotecas que usam 4 estruturas de log diferentes é complicado. Usando o slf4j, você permite que ele configure as estruturas de log que ele deseja. não aquele que você escolheu. Lembre-se de que projetos típicos usam inúmeras bibliotecas, e não apenas a sua.
JB Nizet 06/07

6

Comecei, como você suspeito, a usar o JUL porque era o mais fácil de começar imediatamente. Ao longo dos anos, porém, passei a desejar ter passado um pouco mais de tempo escolhendo.

Meu principal problema agora é que temos uma quantidade substancial de código de 'biblioteca' que é usado em muitos aplicativos e todos eles usam JUL. Sempre que eu uso essas ferramentas em um aplicativo do tipo serviço da Web, o registro desaparece ou vai para algum lugar imprevisível ou estranho.

Nossa solução foi adicionar uma fachada ao código da biblioteca, o que significava que as chamadas de log da biblioteca não foram alteradas, mas foram redirecionadas dinamicamente para qualquer mecanismo de log disponível. Quando incluídos em uma ferramenta POJO, eles são direcionados para JUL, mas quando implantados como um aplicativo Web, são redirecionados para o LogBack.

Lamentamos, é claro, que o código da biblioteca não use o log parametrizado, mas agora ele pode ser adaptado conforme e quando necessário.

Usamos o slf4j para construir a fachada.


11
Por algum motivo você não usou apenas o pacote "redirecionar java.util.logging para slf4j" na distribuição slf4j?
Thorbjørn Ravn Andersen

2
Fizemos isso, mas com pouco valor, porque o principal benefício de mudar para slf4j é o registro parametrizado eficiente. Se tivéssemos usado isso desde o início, não teríamos nenhum trabalho a fazer agora.
OldCurmudgeon

11
Concordo que este é o fruto baixo do slf4j.
Thorbjørn Ravn Andersen

3

Eu executei jul contra slf4j-1.7.21 sobre logback-1.1.7, saída para um SSD, Java 1.8, Win64

jul correu 48449 ms, logback 27185 ms para um loop de 1M.

Ainda assim, um pouco mais de velocidade e uma API um pouco melhor não valem 3 bibliotecas e 800K para mim.

package log;

import java.util.logging.Level;
import java.util.logging.Logger;

public class LogJUL
{
    final static Logger logger = Logger.getLogger(LogJUL.class.getSimpleName());

    public static void main(String[] args) 
    {
        int N = 1024*1024;

        long l = System.currentTimeMillis();

        for (int i = 0; i < N; i++)
        {
            Long lc = System.currentTimeMillis();

            Object[] o = { lc };

            logger.log(Level.INFO,"Epoch time {0}", o);
        }

        l = System.currentTimeMillis() - l;

        System.out.printf("time (ms) %d%n", l);
    }
}

e

package log;

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

public class LogSLF
{
    static Logger logger = LoggerFactory.getLogger(LogSLF.class);


    public static void main(String[] args) 
    {
        int N = 1024*1024;

        long l = System.currentTimeMillis();

        for (int i = 0; i < N; i++)
        {
            Long lc = System.currentTimeMillis();

            logger.info("Epoch time {}", lc);
        }

        l = System.currentTimeMillis() - l;

        System.out.printf("time (ms) %d%n", l);
    }

}

3
Você não está comparando igual por igual. Por que você está criando explicitamente uma matriz para jul? Eu acho que é porque o slf4j não possui uma sobrecarga de um argumento logger.info(). Então você está deliberadamente prejudicando o desempenho do jul para compensar uma falha na interface do slf4j. Em vez disso, você deve codificar os dois métodos da maneira que eles são codificados em idioma.
Klitos Kyriacou

2
Você entendeu errado. Você não precisa usar 800K adicionais. O consenso é que vale a pena usar a API fina do SLF4J, porque você (ou outros que talvez reutilizem um dia o seu código!) Pode alternar livremente entre JUL, Logback, Log4j etc. SLF4J é apenas ~ 28K. A ponte SLF4J para JUL (slf4j-jdk ... jar) tem apenas ~ 9K.
Risco # 22/18
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.