Как я могу получить адреса клиентов для ведения журнала с помощью Grizzly / Jersey?

Я использую Grizzly для обслуживания приложения на Джерси и использую 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 MDC, чтобы сделать адрес сокета клиентов видимым в записи журнала. Для этой цели мне нужно какое-то место для подключения прослушивателя к обработке HTTP, который получает уведомления о входящих запросах (где я могу поместить адрес в MDC) и когда запрос выполнен (чтобы я мог очистить MDC). Один из подходов, который я использовал, заключается в подключении экземпляра 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;
    }

}

К сожалению, Джерси ContainerRequest не предоставляет информацию о подключенном клиенте (что стало настоящим сюрпризом).

Подозреваю, что аналогичный интерфейс должен существовать и у самого Grizzly, но мне не удалось его раскопать.


person Waldheinz    schedule 21.06.2013    source источник


Ответы (2)


Для 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, он же что-то еще). Но в основном это место, где можно зацепиться.

person Waldheinz    schedule 24.06.2013

В вашем 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;
    }
}

Я проверил это, используя аналогичный подход к «зажиганию вещей вручную», и в этом случае это сработало для меня. Я предполагаю, что это сработает и для вас.

person stephen mallette    schedule 22.06.2013
comment
К сожалению, в моем случае HttpServletRequest нет. Мне даже пришлось добавить новую зависимость (я выбрал servlet-api в версии 2.5), чтобы этот интерфейс был доступен. Но даже тогда он не вводится. Это вызывает NullPointerException при разыменовании r. - person Waldheinz; 24.06.2013