web-dev-qa-db-ja.com

JAX-RSを使用して要求と応答を1か所に記録する

多くのメソッドを備えたRESTEasy Webサーバーがあります。すべての要求と応答を追跡するためにログバックを実装したいのですが、すべてのメソッドにlog.info()を追加したくありません。

リクエストとレスポンスを1か所でキャッチしてログに記録する方法があるかもしれません。たぶん、RESTEasyのHTTP要求プロセスチェーンのフィルターのようなものです。

@Path("/rest")
@Produces("application/json")
public class CounterRestService {

    //Don't want use log in controler every method to track requests and responces
    static final Logger log = LoggerFactory.getLogger(CounterRestService.class); 

    @POST
    @Path("/create")
    public CounterResponce create(@QueryParam("name") String name) {
        log.info("create "+name)
        try {
            CounterService.getInstance().put(name);
            log.info("responce data"); // <- :((
            return new CounterResponce();
        } catch (Exception e){
            log.info("responce error data"); // <- :((
            return new CounterResponce("error", e.getMessage());
        }    
    }

    @POST
    @Path("/insert")
    public CounterResponce create(Counter counter) {
        try {
            CounterService.getInstance().put(counter);
            return new CounterResponce();
        } catch (Exception e){
            return new CounterResponce("error", e.getMessage());
        }
    }

    ...
}
27
Edgaras Karka

フィルタを作成して、ログに記録する必要があるエンドポイントに簡単にバインドし、エンドポイントを無駄なくビジネスロジックに集中させることができます。

名前バインディングアノテーションの定義

フィルタをREST=エンドポイントにバインドするために、JAX-RSはメタ注釈 _@NameBinding_ を提供し、次のように使用できます。

_@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Logged { }
_

HTTPリクエストのログ

_@Logged_アノテーションは、 ContainerRequestFilter を実装するフィルタークラスを装飾するために使用され、リクエストを処理できます。

_@Logged
@Provider
public class RequestLoggingFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        // Use the ContainerRequestContext to extract information from the HTTP request
        // Information such as the URI, headers and HTTP entity are available
    }
}
_

_@Provider_ 注釈は、プロバイダースキャンフェーズ中にJAX-RSランタイムが検出できる拡張インターフェースの実装をマークします。

ContainerRequestContext は、HTTPリクエストから情報を抽出するのに役立ちます。

以下は、ログに役立つHTTPリクエストから情報を取得するための ContainerRequestContext AP​​I のメソッドです。

HTTP応答のログ記録

応答を記録するには、 ContainerResponseFilter の実装を検討してください。

_@Logged
@Provider
public class ResponseLoggingFilter implements ContainerResponseFilter {

    @Override
    public void filter(ContainerRequestContext requestContext, 
                       ContainerResponseContext responseContext) throws IOException {
        // Use the ContainerRequestContext to extract information from the HTTP request
        // Use the ContainerResponseContext to extract information from the HTTP response
    }
}
_

ContainerResponseContext は、HTTP応答から情報を抽出するのに役立ちます。

ログに役立つHTTP応答から情報を取得するための ContainerResponseContext AP​​I のメソッドを次に示します。

フィルターをエンドポイントにバインドする

フィルターをエンドポイントのメソッドまたはクラスにバインドするには、上記で定義した_@Logged_アノテーションを使用してアノテーションを付けます。注釈が付けられているメソッドやクラスの場合、フィルターが実行されます。

_@Path("/")
public class MyEndpoint {

    @GET
    @Path("{id}")
    @Produces("application/json")
    public Response myMethod(@PathParam("id") Long id) {
        // This method is not annotated with @Logged
        // The logging filters won't be executed when invoking this method
        ...
    }

    @DELETE
    @Logged
    @Path("{id}")
    @Produces("application/json")
    public Response myLoggedMethod(@PathParam("id") Long id) {
        // This method is annotated with @Logged
        // The request logging filter will be executed before invoking this method
        // The response logging filter will be executed before invoking this method
        ...
    }
}
_

上記の例では、ログフィルターは_@Logged_アノテーションが付けられているため、myLoggedMethod(Long)に対してのみ実行されます。

追加情報

ContainerRequestContext および ContainerResponseFilter インターフェイスで利用可能なメソッドに加えて、 ResourceInfo を注入できます _@Context_ を使用してフィルターで:

_@Context
ResourceInfo resourceInfo;
_

要求されたURLと一致する Method および Class を取得するために使用できます。

_Class<?> resourceClass = resourceInfo.getResourceClass();
Method resourceMethod = resourceInfo.getResourceMethod();
_

HttpServletRequest および HttpServletResponse も注入に使用できます。

_@Context
HttpServletRequest httpServletRequest;

@Context
HttpServletResponse httpServletResponse;
_

_@Context_ で挿入できるタイプについては、これを参照してください answer

70
cassiomolin

インターセプターを試してください(Vanilla EJBインターセプターだけでなく、CDIを使用できます)。

彼らは横断的関心事(側面)を実装するためにそこにいます。

0
Najeeb Arif