如何使用Grizzly / Jersey获取客户端地址以进行日志记录?

我正在使用Grizzly来提供Jersey应用程序,同时使用Logback来满足我的日志记录需求。 请注意,这里没有涉及Servlet ,我使用一段代码“手动”启动所有内容,如下所示:

 final URI uri = /* this is a configuration option */ this.server = new HttpServer(); final NetworkListener nl = new NetworkListener( "grizzly", uri.getHost(), uri.getPort()); server.addListener(nl); final GuiceComponentProviderFactory gcpf = new GuiceComponentProviderFactory(rc, inj); final HttpHandler processor = ContainerFactory.createContainer( HttpHandler.class, rc, gcpf); this.server.getServerConfiguration().addHttpHandler( processor, uri.getPath()); server.start(); 

现在我想使用Logback的MDCfunction使客户端的套接字地址在日志记录中可见。 为此,我需要一些地方来连接一个HTTP处理的监听器,它会收到有关传入请求的通知(我可以将地址放入MDC)以及请求完成时(因此我可以清理MDC)。 我遵循的一种方法是使用Jersey连接Container*Filter实例,如下所示:

 class MdcFilter implements ContainerRequestFilter, ContainerResponseFilter { @Override public ContainerRequest filter(ContainerRequest request) { MDC.put("http-client", "foo" /* no way to get the address here */); return request; } @Override public ContainerResponse filter( ContainerRequest request, ContainerResponse response) { MDC.remove("http-client"); return response; } } 

不幸的是,Jersey ContainerRequest不提供有关连接客户端的信息(这是一个真正的惊喜)。

我怀疑Grizzly本身应该存在类似的界面,但我无法将其挖掘出来。

对于Grizzly,相关的API称为HttpServerProbe 。 使用它,它归结为这样的事情:

 final HttpServer server = new org.glassfish.grizzly.http.server.HttpServer(); server.addListener(new NetworkListener("grizzly", "localhost", 8080)); server.getServerConfiguration().addHttpHandler( new StaticHttpHandler("/var/www/"), "/"); server.getServerConfiguration().getMonitoringConfig().getWebServerConfig() .addProbes(new HttpServerProbe.Adapter() { @Override public void onRequestReceiveEvent( HttpServerFilter filter, Connection connection, Request request) { System.out.println(request.getRemoteAddr()); MDC.put("http-client", request.getRemoteAddr()); } @Override public void onRequestCompleteEvent( HttpServerFilter filter, Connection connection, Response response) { MDC.remove("http-client"); } } server.start(); 

请注意,还有更多可能相关的事件,如暂停,恢复和取消。 这些也应该被处理,特别是如果使用长轮询(又名Comet,又名诸如此类 )。 但基本上这是可以进入的地方。

在你的MdcFilter ,尝试将HttpServletRequest注入你的类并使用它,就像你通常调用getRemoteAddr()或任何其他类似的函数一样:

 class MdcFilter implements ContainerRequestFilter, ContainerResponseFilter { @Context protected HttpServletRequest r; @Override public ContainerRequest filter(ContainerRequest request) { MDC.put("http-client", "foo" r.getRemoteAddr()); return request; } @Override public ContainerResponse filter(ContainerRequest request, ContainerResponse response) { MDC.remove("http-client"); return response; } } 

我使用类似的方法“手动解决问题”对此进行了测试,在这种情况下它对我有用。 我认为它也适合你。