Je travaille sur l'api de repos avec Spring Boot. J'ai besoin de consigner toutes les demandes avec des paramètres d'entrée (avec des méthodes, par exemple GET, POST, etc.), le chemin de la demande, la chaîne de requête, la méthode de classe correspondante à cette demande, ainsi que la réponse de cette action, à la fois le succès et les erreurs.
À titre d'exemple:
demande réussie:
http://example.com/api/users/1
Le journal devrait ressembler à ceci:
{
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 demande avec erreur:
http://example.com/api/users/9999
Le journal devrait ressembler à ceci:
{
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: ...................
]
}
Je souhaite que la demande / réponse soit une entité unique, avec des informations personnalisées liées à cette entité, à la fois dans les cas de réussite et d'erreur.
Quelle est la meilleure pratique au printemps pour y parvenir, peut-être avec des filtres? si oui, pouvez-vous donner un exemple concret?
(J'ai joué avec @ControllerAdvice et @ExceptionHandler, mais comme je l'ai mentionné, je dois gérer toutes les demandes de réussite et d'erreur en un seul endroit (et un seul journal)).
la source
HandlerInterceptor
mais cela peut ne pas fonctionner correctement avec la journalisation de la réponse comme mentionné dans la réponse: concretepage.com/spring/spring-mvc/… - HandlerInterceptor a accès à la méthode (méthode: "UsersController.getUser") cependant. Ce n'est pas connu dans un filtre de servlet.LogClass{ getRequestAndSaveIt()} Gson.toJson(LogClass)
comme pseudocodeRéponses:
N'écrivez pas d'intercepteurs, de filtres, de composants, d'aspects, etc., c'est un problème très courant qui a été résolu plusieurs fois.
Spring Boot dispose d'un module appelé Actuator , qui permet de déconnecter les requêtes HTTP de la boîte. Il y a un point de terminaison mappé à
/trace
(SB1.x) ou/actuator/httptrace
(SB2.0 +) qui vous montrera les 100 dernières requêtes HTTP. Vous pouvez le personnaliser pour enregistrer chaque demande ou écrire dans une base de données.Pour obtenir les points de terminaison que vous souhaitez, vous aurez besoin de la dépendance Spring-boot-starter-actuator, ainsi que de la "liste blanche" des points de terminaison que vous recherchez, et éventuellement configurer ou désactiver la sécurité pour cela.
De plus, où cette application s'exécutera-t-elle? Allez-vous utiliser un PaaS? Les fournisseurs d'hébergement, Heroku par exemple, fournissent la journalisation des demandes dans le cadre de leur service et vous n'avez alors pas besoin de faire de codage.
la source
Spring fournit déjà un filtre qui fait ce travail. Ajoutez le bean suivant à votre configuration
N'oubliez pas de changer le niveau de journalisation
org.springframework.web.filter.CommonsRequestLoggingFilter
enDEBUG
.la source
Vous pouvez utiliser
javax.servlet.Filter
s'il n'était pas nécessaire de consigner la méthode java qui a été exécutée.Mais avec cette exigence que vous avez des informations d'accès stockées dans
handlerMapping
desDispatcherServlet
. Cela dit, vous pouvez remplacerDispatcherServlet
pour effectuer la journalisation de la paire demande / réponse.Vous trouverez ci-dessous un exemple d'idée qui peut être encore améliorée et adaptée à vos besoins.
HandlerExecutionChain
- contient les informations sur le gestionnaire de requêtes.Vous pouvez ensuite enregistrer ce répartiteur comme suit:
Et voici l'exemple de journaux:
METTRE À JOUR
En cas d'erreurs, Spring gère automatiquement les erreurs. Par conséquent,
BasicErrorController#error
s'affiche comme gestionnaire de demandes. Si vous souhaitez conserver le gestionnaire de requêtes d'origine, vous pouvez remplacer ce comportement lors de l' appelspring-webmvc-4.2.5.RELEASE-sources.jar!/org/springframework/web/servlet/DispatcherServlet.java:971
avant#processDispatchResult
, pour mettre en cache le gestionnaire d'origine.la source
La bibliothèque Logbook est spécialement conçue pour la journalisation des requêtes et réponses HTTP. Il prend en charge Spring Boot à l'aide d'une bibliothèque de démarrage spéciale.
Pour activer la journalisation dans Spring Boot, il vous suffit d'ajouter la bibliothèque aux dépendances de votre projet. Par exemple, en supposant que vous utilisez Maven:
Par défaut, la sortie de journalisation ressemble à ceci:
Toutefois, il ne génère pas le nom de classe qui gère la demande. La bibliothèque possède quelques interfaces pour écrire des enregistreurs personnalisés.
la source
logging.level.org.zalando.logbook=TRACE
à votreapplication.properties
(comme indiqué dans leReadme
)J'avais défini le niveau de connexion
application.properties
pour imprimer les demandes / réponses, l'url de la méthode dans le fichier journalJ'avais utilisé Spring Boot.
la source
Voici comment je le fais au printemps, les données reposent en utilisant
org.springframework.web.util.ContentCachingRequestWrapper
etorg.springframework.web.util.ContentCachingResponseWrapper
la source
Si cela ne vous dérange pas d'essayer Spring AOP, c'est quelque chose que j'ai exploré à des fins de journalisation et cela fonctionne assez bien pour moi. Il n'enregistrera pas les demandes qui n'ont pas été définies et les tentatives de demande ont échoué.
Ajoutez ces trois dépendances
Ajoutez ceci à votre fichier de configuration xml
<aop:aspectj-autoproxy/>
Créer une annotation pouvant être utilisée comme point de coupe
Annotez maintenant toutes vos méthodes d'API de repos que vous souhaitez enregistrer
Passons maintenant à l'Aspect. scanner les composants du package dans lequel se trouve cette classe.
Si vous voulez lire en détail, lisez ceci. http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html
la source
Après avoir ajouté des actionneurs à l'application bassed Spring Boot, vous disposez d'un
/trace
point de terminaison avec les dernières informations sur les demandes. Ce point de terminaison fonctionne sur la base de TraceRepository et l'implémentation par défaut est InMemoryTraceRepository qui enregistre les 100 derniers appels. Vous pouvez changer cela en implémentant cette interface par vous-même et en la rendant disponible en tant que bean Spring. Par exemple, pour consigner toutes les demandes de consignation (et toujours utiliser l'implémentation par défaut comme stockage de base pour diffuser des informations sur le/trace
point de terminaison), j'utilise ce type d'implémentation:Cette
traceInfo
carte contient des informations de base sur demande et la réponse à ce genre de forme:{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}}}
. Il n'y a AUCUN contenu de réponse ici.ÉDITER! Journalisation des données POST
Vous pouvez accéder aux données POST en remplaçant WebRequestTraceFilter , mais ne pensez pas que ce soit une bonne idée (par exemple, tout le contenu du fichier téléchargé ira dans les journaux) Voici un exemple de code, mais ne le faites pas utilisez pas:
la source
TraceRepository
, comment pouvons-nous y accéder?protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
mais je ne sais pas quand ce filtre est exécuté - peut être en phase de demande, donc le corps de réponse ne sera pas prêt là-bas.Ce code fonctionne pour moi dans une application Spring Boot - il suffit de l'enregistrer en tant que filtre
la source
Actuellement, Spring Boot a la fonction Actuator pour obtenir les journaux des demandes et des réponses.
Mais vous pouvez également obtenir les journaux en utilisant Aspect (AOP).
Aspect vous fournit des annotations telles que :
@Before
,@AfterReturning
,@AfterThrowing
etc.@Before
consigne la demande,@AfterReturning
consigne la réponse et@AfterThrowing
enregistre le message d'erreur. Vous n'avez peut-être pas besoin du journal de tous les points de terminaison, vous pouvez donc appliquer certains filtres sur les packages.Voici quelques exemples :
Pour demande:
Ici
@Before("within(your.package.where.endpoints.are..*)")
le chemin du package. Tous les points de terminaison de ce package généreront le journal.Pour réponse:
Voici
@AfterReturning("within(your.package.where.endpoints.are..*)")
le chemin du package. Tous les points de terminaison de ce package généreront le journal. AussiObject returnValue
la réponse.Par exception:
Voici
@AfterThrowing(pointcut = ("within(your.package.where.endpoints.are..*)"), throwing = "e")
le chemin du package. Tous les points de terminaison de ce package généreront le journal. AussiException e
la réponse d'erreur.Voici le code complet:
Ici, en utilisant,
@ConditionalOnExpression("${endpoint.aspect.enabled:true}")
vous pouvez activer / désactiver le journal. il suffit d'ajouterendpoint.aspect.enabled:true
dans leapplication.property
et de contrôler le journalPlus d'informations sur la visite AOP ici:
Quais de printemps sur l'AOP
Exemple d'article sur AOP
la source
new ObjectMapper()
coûte cher, mieux vaut partager un mappeur pour tousVoici ma solution (Spring 2.0.x)
Ajoutez la dépendance maven:
Modifiez le fichier application.properties et ajoutez la ligne suivante:
Une fois votre application Spring Boot démarrée, vous pouvez suivre les 100 dernières requêtes http en appelant cette URL: http: // localhost: 8070 / actuator / httptrace
la source
Vous pouvez également configurer un intercepteur Spring personnalisé
HandlerInterceptorAdapter
pour une implémentation simplifiée des intercepteurs avant / après seulement:Ensuite, vous enregistrez autant d'intercepteurs que vous le souhaitez:
Remarque: comme indiqué par @Robert , vous devez faire attention aux implémentations spécifiques de et que votre application utilise.
HttpServletRequest
HttpServletResponse
Par exemple, pour les applications utilisant le
ShallowEtagHeaderFilter
, l'implémentation de la réponse serait unContentCachingResponseWrapper
, vous auriez donc:la source
@ la réponse de hahn nécessité un peu de modification pour que cela fonctionne pour moi, mais c'est de loin la chose la plus personnalisable que j'ai pu obtenir.
Cela n'a pas fonctionné pour moi, probablement parce que j'ai également un HandlerInterceptorAdapter [??] mais j'ai continué à recevoir une mauvaise réponse du serveur dans cette version. Voici ma modification.
la source
Si quelqu'un en a encore besoin, voici une implémentation simple avec Spring HttpTrace Actuator. Mais comme ils l'ont dit plus haut, cela ne fait pas enregistrer les corps.
la source
Veuillez vous référer au lien ci-dessous pour la réponse réelle https://gist.github.com/int128/e47217bebdb4c402b2ffa7cc199307ba
Quelques modifications ont été apportées à la solution référencée ci-dessus, la demande et la réponse se connecteront également à la console et au fichier si le niveau de l'enregistreur est info. nous pouvons imprimer dans la console ou dans un fichier.
Sortie dans un fichier:
la source
Si vous ne voyez qu'une partie de la charge utile de votre demande, vous devez appeler la
setMaxPayloadLength
fonction car elle affiche par défaut seulement 50 caractères dans votre corps de demande. En outre, la valeursetIncludeHeaders
false est une bonne idée si vous ne souhaitez pas enregistrer vos en-têtes d'authentification!la source
si vous utilisez Tomcat dans votre application de démarrage, voici
org.apache.catalina.filters.RequestDumperFilter
un chemin de classe pour vous. (mais il ne vous fournira pas "d'exceptions au même endroit").la source
le code collé ci-dessous fonctionne avec mes tests et peut être téléchargé depuis mon [projet github] [1], en partageant après avoir appliqué une solution basée sur celle-ci sur un projet de production.
la source
Afin de consigner toutes les demandes avec des paramètres d'entrée et un corps, nous pouvons utiliser des filtres et des intercepteurs . Mais lors de l'utilisation d'un filtre ou d'un intercepteur, nous ne pouvons pas imprimer le corps de la demande plusieurs fois. La meilleure façon est d'utiliser Spring-AOP. En l'utilisant, nous pouvons dissocier le mécanisme de journalisation de l'application. AOP peut être utilisé pour enregistrer l' entrée et la sortie de chaque méthode dans l'application.
Ma solution est:
}
la source
Si vous avez configuré le serveur Spring Boot Config, il vous suffit d'activer l'enregistreur de débogage pour la classe:
Http11InputBuffer.Http11InputBuffer.java
Les débogages consignent toutes les demandes et réponses pour chaque demande
la source
Pour enregistrer les demandes qui aboutissent à 400 uniquement:
la source