class AccessLogFilter implements ContainerResponseFilter {

    private static final Logger LOG = Log.logger(AccessLogFilter.class);

    private static final String DELIMITER = "/";
    private static final String GRAPHS = "graphs";
    private static final String GREMLIN = "gremlin";
    private static final String CYPHER = "cypher";

    @Context
    private jakarta.inject.Provider<HugeConfig> configProvider;

    @Context
    private jakarta.inject.Provider<GraphManager> managerProvider;

    public static boolean needRecordLog(ContainerRequestContext context) {
        // TODO: add test for 'path' result ('/gremlin' or 'gremlin')
        String path = context.getUriInfo().getPath();

        // GraphsAPI/CypherAPI/Job GremlinAPI
        if (path.startsWith(GRAPHS)) {
            if (HttpMethod.GET.equals(context.getMethod()) || path.endsWith(CYPHER)) {
                return true;
            }
        }
        // Direct GremlinAPI
        return path.endsWith(GREMLIN);
    }

    private String join(String path1, String path2) {
        return String.join(DELIMITER, path1, path2);
    }

    /**
     * Use filter to log request info
     *
     * @param requestContext  requestContext
     * @param responseContext responseContext
     */
    @Override
    public void filter(ContainerRequestContext requestContext,
                       ContainerResponseContext responseContext) throws IOException {<FILL_FUNCTION_BODY>}

    private boolean statusOk(int status) {
        return status >= 200 && status < 300;
    }
}

        // Grab corresponding request / response info from context;
        URI uri = requestContext.getUriInfo().getRequestUri();
        String path = uri.getRawPath();
        String method = requestContext.getMethod();
        String metricsName = join(path, method);

        MetricsUtil.registerCounter(join(metricsName, METRICS_PATH_TOTAL_COUNTER)).inc();
        if (statusOk(responseContext.getStatus())) {
            MetricsUtil.registerCounter(join(metricsName, METRICS_PATH_SUCCESS_COUNTER)).inc();
        } else {
            MetricsUtil.registerCounter(join(metricsName, METRICS_PATH_FAILED_COUNTER)).inc();
        }

        Object requestTime = requestContext.getProperty(REQUEST_TIME);
        if (requestTime != null) {
            long now = System.currentTimeMillis();
            long start = (Long) requestTime;
            long executeTime = now - start;

            MetricsUtil.registerHistogram(join(metricsName, METRICS_PATH_RESPONSE_TIME_HISTOGRAM))
                       .update(executeTime);

            HugeConfig config = configProvider.get();
            long timeThreshold = config.get(ServerOptions.SLOW_QUERY_LOG_TIME_THRESHOLD);
            // Record slow query if meet needs, watch out the perf
            if (timeThreshold > 0 && executeTime > timeThreshold &&
                needRecordLog(requestContext)) {
                // TODO: set RequestBody null, handle it later & should record "client IP"
                LOG.info("[Slow Query] execTime={}ms, body={}, method={}, path={}, query={}",
                         executeTime, null, method, path, uri.getQuery());
            }
        }

        // Unset the context in "HugeAuthenticator", need distinguish Graph/Auth server lifecycle
        GraphManager manager = managerProvider.get();
        // TODO: transfer Authorizer if we need after.
        if (manager.requireAuthentication()) {
            manager.unauthorize(requestContext.getSecurityContext());
        }
    
<no_super_class>