Registrando respostas de RestTemplate

5

Eu quero registrar as respostas usando RestTemplate do Spring. No começo eu pensei que deveria fazê-lo usando um ClientHttpRequestInterceptor , mas como cada conjunto de solicitações deve ser registrado em um arquivo diferente, descobri que deveria criar um novo RestTemplate com um novo ClientHttpRequestInterceptor para cada conjunto de solicitações (embora todas as outras configurações sejam as mesmas).

Mas eu vi que RestTemplate é um objeto muito caro para criar, quando cerca de 70% do tempo de criação, está criando o MessageConverters .

Então - existe uma maneira melhor de implementar esse requisito? É possível compartilhar MessageConverters em várias instâncias de RestTemplate , portanto, melhorar significativamente o desempenho?

EDITAR Aqui está uma amostra do meu código:

protected MyResponse<MyInterface> getInterfaces(RestTemplate restClient, RestParams inputParams, String cookie, File outputFile) {

    Request devInterfacesRequest = getRequest(RequestType.INTERFACES, inputParams, cookie);

    return restClient.postForObject(inputParams.getUrl(), devInterfacesRequest , new ParameterizedTypeReference<MyResponse<MyInterface>>(){});
}

Onde posso adicionar o outputFile?

    
por Nati 19.04.2016 / 23:10
fonte

1 resposta

1

Bem, eu tenho pensado nessa questão e é isso que eu recebo:

Restrições

Citando o proprietário da pergunta:

  1. Implementar meu próprio RestTemplate é pesado

But I saw that RestTemplate is pretty expensive object to create, when about 70% of the creation time, is creating the MessageConverters.

  1. RestTemplate não é thread-safe após a construção. Mas não é após a construção . Veja mais O segmento RestTemplate é seguro?

Conceptually, it is very similar to the JdbcTemplate, JmsTemplate, and the various other templates found in the Spring Framework and other portfolio projects. This means, for instance, that the RestTemplate is thread-safe once constructed

Este último recurso está sugerindo não modificar um RestTemplate após sua construção. Então eu não adicionaria nenhum novo Interceptor nem o removeria

  1. Sentimos falta de muitos detalhes sobre o sistema e seus requisitos, limites, etc.

  2. Não sabemos para que servem esses arquivos. Por isso, compromete a adequação da solução que proponho.

O que temos?

Se eu estiver certo, temos Log4J do Appache configurado. ( @Nati me contou por chat ).

Então, decidi usar o Log4j como ferramenta de registro. No entanto, confira a seção Desvantagens . ( espero que alguém que leia esta resposta possa dissipar minhas dúvidas )

Por que Log4j ao invés do meu próprio gerenciamento de arquivos? Porque eu queria delegar ao Log4j os seguintes recursos: acesso a arquivos , uso de padrões , uso de filtros (opcional) , uso de níveis , ...

Solução

LoggerHelper

Eu implementei um auxiliar para tornar a solução portátil através de qualquer camada com o menor acoplamento possível.

package org.myworkouts.helper;

import java.io.File;
import java.io.IOException;

import org.apache.log4j.FileAppender;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;


public class LoggerHelper {

    // Helper's own logger
    private static final Logger LOGGER = LogManager
            .getLogger(LoggerHelper.class);
    private static final String DEFAULT_LOG_PATTERN = "%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n";
    private static final String LOGGER_PREFIX = "logger";
    private static final String APPENDER_PREFIX = "appender";

    private static LoggerHelper instance = null;

    // Singleton
    private LoggerHelper() {
        super();
    }

    public static LoggerHelper getInstance() {
        if (instance == null) {
            instance = new LoggerHelper();
        }
        return instance;
    }

    /**
     * Get the logger by its name or create if never was instanciated previously
     * 
     * @throws IOException
     */
    public Logger getCustomFileLogger(String filePath) throws IOException {
        String loggerName = resolveLoggerName(filePath);

        Logger logger = LogManager.exists(loggerName);
        if (logger == null) {
            LOGGER.info("Creating new Logger: ".concat(loggerName));
            logger = LogManager.getLogger(loggerName);
        }
        setLevel(logger, Level.INFO).addFileAppender(logger, filePath);
        return logger;
    }

    private LoggerHelper addFileAppender(Logger logger, String filePath)
            throws IOException {
        if (logger != null) {
            String appenderName = resolveAppenderName(filePath);
            if (logger.getAppender(appenderName) == null) {
                logger.addAppender(new FileAppender(new PatternLayout(
                        DEFAULT_LOG_PATTERN), filePath, Boolean.TRUE));
            }
        }
        return this;
    }

    private LoggerHelper setLevel(Logger logger, Level level) {
        if (logger != null) {
            logger.setLevel(level);
        }
        return this;
    }

    /* Optionl. Generate a custom name for a new Appender */
    private String resolveAppenderName(String filePath) {
        return APPENDER_PREFIX.concat(File.pathSeparator).concat(
                getNameWithoutExtension(filePath));
    }

    /* Optionl. Generate a custom name for a new Logger */
    private String resolveLoggerName(String filePath) {
        return LOGGER_PREFIX.concat(File.pathSeparator).concat(
                getNameWithoutExtension(filePath));
    }

    //Took from com.google.common.io.Files
    //I had it in my workspace but I didn't want to use it at this
    //class
    private String getNameWithoutExtension(String filePath) {
        String fileName = new File(filePath).getName();
        int dotIndex = fileName.lastIndexOf('.');
        return (dotIndex == -1) ? fileName : fileName.substring(0, dotIndex);
    }
}

Implementação

Anexando a solução ao código do proprietário

protected MyResponse<MyInterface> getInterfaces(RestTemplate restClient, RestParams inputParams, String cookie, File outputFile) {

    Request devInterfacesRequest = getRequest(RequestType.INTERFACES, inputParams, cookie);

     MyResponse<MyInterface> response =  restClient.postForObject(inputParams.getUrl(), devInterfacesRequest , new ParameterizedTypeReference<MyResponse<MyInterface>>(){});
     try{
           Logger customLogger = LoggerHelper.getInstance().getCustomFileLogger(outputFile.getPath());
           //... we can also to parse it to Json, XML, whatever...
           customLogger.info(response.toString());
     }catch(IOException ex){
          //... what do we have to do if logger could not be instanciated?
     }
     return response;
}

Observação : A implementação também pode ser movida para getInterfaces do chamador que tem (eu suponho) um for bucle e também decide o outputFile . Então getCustomFileLogger(...) seria invocado apenas uma vez.

Teste

public class LoggerHelperTest {

    public static final Logger LOGGER = LogManager.getLogger(LoggerHelperTest.class);

    @Test
    public void getCustomLoggerTest() throws IOException{
        Logger customLogger = LoggerHelper.getInstance().getCustomFileLogger("file.txt");
        Assert.assertNotNull("CustomLogger should not be null",customLogger);
        Assert.assertEquals("CustomLogger's level should be INFO by default",Level.INFO, customLogger.getLevel());
        Assert.assertTrue("CustomLogger's name should contain file's name on its name",customLogger.getName().contains("file"));
        customLogger.info("Trace 1");
        customLogger.info("Trace 2");
        customLogger.info("Trace 3");
    }
}

arquivo.txt

A saída que recebi

2016-05-03 13:38:56 INFO  logger:file:47 - Trace 1
2016-05-03 13:38:56 INFO  logger:file:48 - Trace 2
2016-05-03 13:38:56 INFO  logger:file:49 - Trace 3

Dúvidas

Esta é uma sugestão. Está aberto a sugestões ou melhorias. Eu também tenho minhas dúvidas sobre minha solução. ( eu não enfatizei a solução ):

  1. O arquivo File está bloqueado (aberto) por qualquer outro processo? Então IOException será lançado.
  2. Início quaisquer diferenças outputFile são? 10,100,1000? Podemos ter tantos loggers no Log4j?
  3. Esses outputFile serão movidos em tempo de execução? Se alguma for movida / excluída / substituída, o log4j não conseguirá manter o login.
  4. Vamos pegar o IOException em vez de deixá-lo ir ?. Eu delego ao usuário do LoggerHelper para decidir o que fazer ...

Eu usei o Log4j porque tenho em mente que o requisito é manter os registradores separados, imprimindo todos em seu próprio arquivo. Mas eu espero que eles só contenham rastreamentos de log ( para mais revisões ou debugs ).

No entanto, se o conteúdo do arquivo for importante, se o conteúdo for importante para nós, a solução não será adequada.

Se o conteúdo é importante e eu não quero implementar um gerenciamento de arquivos , eu pensaria em armazenar esses logs em noSQL db (mongoDB ou qualquer outro mais adequado para nossa plataforma) que também é capaz de suportar um alto volume de dados. Os dados podem ser obtidos posteriormente com solicitações adequadas

    
por 03.05.2016 / 14:29
fonte