Estou trabalhando na API de repouso com bota de mola. Eu preciso registrar todas as solicitações com parâmetros de entrada (com métodos, por exemplo, GET, POST, etc), caminho da solicitação, sequência de consultas, método de classe correspondente dessa solicitação, também resposta dessa ação, tanto sucesso quanto erros.
Por exemplo:
solicitação bem-sucedida:
http://example.com/api/users/1
Log deve ser algo parecido com isto:
{
HttpStatus: 200,
path: "api/users/1",
method: "GET",
clientIp: "0.0.0.0",
accessToken: "XHGu6as5dajshdgau6i6asdjhgjhg",
method: "UsersController.getUser",
arguments: {
id: 1
},
response: {
user: {
id: 1,
username: "user123",
email: "[email protected]"
}
},
exceptions: []
}
Ou peça com erro:
http://example.com/api/users/9999
Log deve ser algo como isto:
{
HttpStatus: 404,
errorCode: 101,
path: "api/users/9999",
method: "GET",
clientIp: "0.0.0.0",
accessToken: "XHGu6as5dajshdgau6i6asdjhgjhg",
method: "UsersController.getUser",
arguments: {
id: 9999
},
returns: {
},
exceptions: [
{
exception: "UserNotFoundException",
message: "User with id 9999 not found",
exceptionId: "adhaskldjaso98d7324kjh989",
stacktrace: ...................
]
}
Desejo que Solicitação / Resposta seja uma entidade única, com informações personalizadas relacionadas a essa entidade, tanto em casos de sucesso quanto de erro.
Qual é a melhor prática na primavera para conseguir isso, pode ser com filtros? Se sim, você pode fornecer um exemplo concreto?
(Joguei com @ControllerAdvice e @ExceptionHandler, mas, como mencionei, preciso lidar com todas as solicitações de sucesso e erro em um único local (e em um único log)).
fonte
HandlerInterceptor
, mas que pode não funcionar bem com registrando a resposta como mencionado na resposta: concretepage.com/spring/spring-mvc/... - HandlerInterceptor tem acesso para o método (método: "UsersController.getUser"). Isso não é conhecido em um filtro de servlet.LogClass{ getRequestAndSaveIt()} Gson.toJson(LogClass)
como pseudocódigoRespostas:
Não escreva interceptores, filtros, componentes, aspectos etc., este é um problema muito comum e foi resolvido várias vezes.
O Spring Boot possui um módulo chamado Actuator , que fornece o log de solicitação HTTP pronto para uso. Há um ponto de extremidade mapeado para
/trace
(SB1.x) ou/actuator/httptrace
(SB2.0 +) que mostrará as últimas 100 solicitações HTTP. Você pode personalizá-lo para registrar cada solicitação ou gravar em um banco de dados.Para obter os terminais desejados, você precisará da dependência spring-boot-starter-actuator, além de "colocar na lista branca" os terminais desejados e, possivelmente, configurar ou desativar a segurança.
Além disso, onde esse aplicativo será executado? Você usará um PaaS? Os provedores de hospedagem, Heroku por exemplo, fornecem o registro de solicitações como parte de seu serviço e você não precisa fazer nenhuma codificação.
fonte
O Spring já fornece um filtro que faz esse trabalho. Adicione o bean a seguir à sua configuração
Não se esqueça de alterar o nível do log de
org.springframework.web.filter.CommonsRequestLoggingFilter
paraDEBUG
.fonte
Você poderia usar
javax.servlet.Filter
se não houvesse um requisito para registrar o método java que foi executado.Mas com este requisito você tem que acessar informações armazenadas em
handlerMapping
deDispatcherServlet
. Dito isto, você pode substituirDispatcherServlet
para realizar o log do par de solicitação / resposta.Abaixo está um exemplo de idéia que pode ser aprimorado e adotado de acordo com suas necessidades.
HandlerExecutionChain
- contém as informações sobre o manipulador de solicitações.Você pode registrar esse expedidor da seguinte maneira:
E aqui está a amostra de logs:
ATUALIZAR
Em caso de erros, o Spring realiza o tratamento automático de erros. Portanto,
BasicErrorController#error
é mostrado como manipulador de solicitações. Se você quiser preservar o manipulador de solicitações original, poderá substituir esse comportamentospring-webmvc-4.2.5.RELEASE-sources.jar!/org/springframework/web/servlet/DispatcherServlet.java:971
antes de#processDispatchResult
ser chamado, para armazenar em cache o manipulador original.fonte
O diário de bordo biblioteca foi criada especificamente para registrar solicitações e respostas HTTP. Ele suporta o Spring Boot usando uma biblioteca inicial especial.
Para habilitar o log no Spring Boot, tudo o que você precisa fazer é adicionar a biblioteca às dependências do seu projeto. Por exemplo, supondo que você esteja usando o Maven:
Por padrão, a saída do registro se parece com isso:
No entanto, ele não gera o nome da classe que está manipulando a solicitação. A biblioteca possui algumas interfaces para gravar registradores personalizados.
fonte
logging.level.org.zalando.logbook=TRACE
ao seuapplication.properties
(como é afirmado noReadme
)Eu havia definido o nível de logon
application.properties
para imprimir solicitações / respostas, URL do método no arquivo de logEu tinha usado o Spring Boot.
fonte
Aqui está como eu faço isso no resto dos dados da primavera usando
org.springframework.web.util.ContentCachingRequestWrapper
eorg.springframework.web.util.ContentCachingResponseWrapper
fonte
Se você não se importa de tentar o Spring AOP, isso é algo que venho explorando para fins de registro e funciona muito bem para mim. Porém, ele não registra solicitações que não foram definidas e falhou nas tentativas de solicitação.
Adicione essas três dependências
Adicione isso ao seu arquivo de configuração xml
<aop:aspectj-autoproxy/>
Crie uma anotação que possa ser usada como um corte de ponto
Agora anote todos os seus métodos API restantes que você deseja registrar
Agora vamos ao Aspecto. faça a varredura de componentes do pacote em que esta classe está.
Se você quiser ler em detalhes, leia isso. http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html
fonte
Após adicionar os Atuadores ao aplicativo de inicialização com mola, você tem um
/trace
terminal disponível com as informações mais recentes sobre solicitações. Esse terminal está funcionando com base no TraceRepository e a implementação padrão é InMemoryTraceRepository, que salva as últimas 100 chamadas. Você pode mudar isso implementando essa interface por conta própria e disponibilizando-a como um bean Spring. Por exemplo, para registrar todas as solicitações para registrar (e ainda usar a implementação padrão como um armazenamento básico para fornecer informações sobre o/trace
endpoint), estou usando este tipo de implementação:Este
traceInfo
mapa contém informações básicas sobre pedido e resposta neste tipo de forma:{method=GET, path=/api/hello/John, headers={request={host=localhost:8080, user-agent=curl/7.51.0, accept=*/*}, response={X-Application-Context=application, Content-Type=text/plain;charset=UTF-8, Content-Length=10, Date=Wed, 29 Mar 2017 20:41:21 GMT, status=200}}}
. Não há conteúdo de resposta aqui.EDITAR! Registrando Dados POST
Você pode acessar os dados do POST substituindo WebRequestTraceFilter , mas não é uma boa ideia (por exemplo, todo o conteúdo do arquivo carregado irá para os logs) Aqui está o código de exemplo, mas não o use:
fonte
TraceRepository
, como podemos acessar isso?protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
mas não tenho certeza quando esse filtro é executado - pode estar na fase de solicitação, portanto, o corpo da resposta não estará pronto lá.Esse código funciona para mim em um aplicativo Spring Boot - basta registrá-lo como um filtro
fonte
Aqui está minha solução (Spring 2.0.x)
Adicione a dependência do maven:
Edite o application.properties e inclua a seguinte linha:
Depois que o aplicativo de inicialização do Spring for iniciado, você poderá rastrear as 100 solicitações HTTP mais recentes chamando este URL: http: // localhost: 8070 / actuator / httptrace
fonte
Atualmente, o Spring Boot possui o recurso Atuador para obter os logs de solicitações e respostas.
Mas você também pode obter os logs usando o Aspect (AOP).
Aspect fornece-lhe com anotações como:
@Before
,@AfterReturning
,@AfterThrowing
etc.@Before
registra a solicitação,@AfterReturning
registra a resposta e@AfterThrowing
registra a mensagem de erro. Talvez você não precise do log de todos os pontos de extremidade para poder aplicar alguns filtros nos pacotes.Aqui estão alguns exemplos :
Para Pedido:
Aqui
@Before("within(your.package.where.endpoints.are..*)")
tem o caminho do pacote. Todos os terminais neste pacote gerarão o log.Para resposta:
Aqui
@AfterReturning("within(your.package.where.endpoints.are..*)")
tem o caminho do pacote. Todos os terminais neste pacote gerarão o log. TambémObject returnValue
contém a resposta.Para exceção:
Aqui
@AfterThrowing(pointcut = ("within(your.package.where.endpoints.are..*)"), throwing = "e")
tem o caminho do pacote. Todos os terminais neste pacote gerarão o log. TambémException e
contém a resposta do erro.Aqui está o código completo:
Aqui,
@ConditionalOnExpression("${endpoint.aspect.enabled:true}")
você pode ativar / desativar o log. basta adicionarendpoint.aspect.enabled:true
noapplication.property
e controlar o logMais informações sobre a AOP visite aqui:
Docas de primavera sobre AOP
Exemplo de artigo sobre AOP
fonte
new ObjectMapper()
é caro, melhor compartilham um mapeador para todosVocê também pode configurar um interceptor Spring personalizado
HandlerInterceptorAdapter
para uma implementação simplificada de interceptores pré-somente / pós-somente:Em seguida, você registra quantos interceptores desejar:
Nota: assim como declarado pelo @Robert , você precisa prestar atenção nas implementações específicas e no aplicativo que está usando.
HttpServletRequest
HttpServletResponse
Por exemplo, para aplicativos que usam o
ShallowEtagHeaderFilter
, a implementação da resposta seria aContentCachingResponseWrapper
, então você teria:fonte
A resposta do @ hahn exigiu algumas modificações para funcionar para mim, mas é de longe a coisa mais personalizável que eu poderia ter.
Não funcionou para mim, provavelmente porque também tenho um HandlerInterceptorAdapter [??], mas continuava recebendo uma resposta ruim do servidor nessa versão. Aqui está a minha modificação.
fonte
Se alguém ainda precisar, aqui é uma implementação simples com o Spring HttpTrace Actuator. Mas, como disseram acima, não registra os corpos.
fonte
Consulte o link abaixo para obter a resposta real https://gist.github.com/int128/e47217bebdb4c402b2ffa7cc199307ba
Feitas algumas alterações na solução acima mencionada, a solicitação e a resposta também farão login no console e no arquivo se o nível do registrador for info. podemos imprimir no console ou no arquivo.
Saída no arquivo:
fonte
Se você estiver vendo apenas parte da carga útil da sua solicitação, precisará chamar a
setMaxPayloadLength
função, pois o padrão é mostrar apenas 50 caracteres no corpo da solicitação. Além disso, definirsetIncludeHeaders
como false é uma boa ideia se você não deseja registrar seus cabeçalhos de autenticação!fonte
se você usar o Tomcat no seu aplicativo de inicialização, aqui está
org.apache.catalina.filters.RequestDumperFilter
um caminho de classe para você. (mas não fornecerá "exceções em um único local").fonte
o código colado abaixo funciona com meus testes e pode ser baixado do meu [projeto github] [1], compartilhando após a aplicação de uma solução baseada em um projeto de produção.
fonte
Para registrar todas as solicitações com parâmetros e corpo de entrada, podemos usar filtros e interceptadores . Porém, ao usar um filtro ou interceptador, não podemos imprimir o corpo da solicitação várias vezes. A melhor maneira é que podemos usar o Spring-AOP. Ao usar isso, podemos dissociar o mecanismo de log do aplicativo. O AOP pode ser usado para registrar a entrada e a saída de cada método no aplicativo.
Minha solução é:
}
fonte
Se você tiver o servidor Spring Boot Config configurado, ative o Debug logger da classe:
Http11InputBuffer.Http11InputBuffer.java
Debuga registrará todos os pedidos e respostas para cada pedido
fonte
Para registrar solicitações que resultam em apenas 400:
fonte