All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hu.icellmobilsoft.coffee.grpc.server.interceptor.ServerResponseInterceptor Maven / Gradle / Ivy

The newest version!
/*-
 * #%L
 * Coffee
 * %%
 * Copyright (C) 2020 - 2023 i-Cell Mobilsoft Zrt.
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package hu.icellmobilsoft.coffee.grpc.server.interceptor;

import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Optional;
import java.util.Set;

import jakarta.enterprise.inject.spi.Bean;
import jakarta.enterprise.inject.spi.CDI;

import org.apache.commons.lang3.StringUtils;

import hu.icellmobilsoft.coffee.grpc.server.log.GrpcLogging;
import hu.icellmobilsoft.coffee.rest.log.annotation.LogSpecifier;
import hu.icellmobilsoft.coffee.rest.log.annotation.enumeration.LogSpecifierTarget;
import hu.icellmobilsoft.coffee.se.logging.DefaultLogger;
import hu.icellmobilsoft.coffee.se.logging.Logger;
import io.grpc.ForwardingServerCall.SimpleForwardingServerCall;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import io.grpc.ServerCall;
import io.grpc.ServerCall.Listener;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import io.grpc.Status;

/**
 * gRPC response interceptor example
 * 
 * @author czenczl
 * @author Imre Scheffer
 * @since 2.1.0
 *
 */
public class ServerResponseInterceptor implements ServerInterceptor {

    private static final Logger LOGGER = DefaultLogger.getLogger(ServerResponseInterceptor.class);

    /**
     * Default constructor, constructs a new object.
     */
    public ServerResponseInterceptor() {
        super();
    }

    @Override
    public  Listener interceptCall(ServerCall serverCall, Metadata metadata, ServerCallHandler next) {

        // it's fix on startup, maybe it should be cached
        int responseLogSize = getResponseLogSize(serverCall.getMethodDescriptor());

        ServerCall forwardingServerCall = new SimpleForwardingServerCall<>(serverCall) {

            StringBuilder messageToPrint = new StringBuilder();
            int count = 0;

            @Override
            public void sendMessage(RespT message) {
                GrpcLogging.handleMdc();
                String part = "[#" + ++count + "#]\n";
                if (responseLogSize > LogSpecifier.UNLIMIT) {
                    if (messageToPrint.length() < responseLogSize) {
                        messageToPrint.append(part).append(StringUtils.truncate(message.toString(), responseLogSize - messageToPrint.length()));
                        if (messageToPrint.length() >= responseLogSize) {
                            messageToPrint.append("...");
                        }
                    }
                } else {
                    messageToPrint.append(part).append(message.toString());
                }
                super.sendMessage(message);
            }

            @Override
            public void close(Status status, Metadata trailers) {
                GrpcLogging.handleMdc();
                String serviceName = serverCall.getMethodDescriptor().getServiceName();
                String methodName = serverCall.getMethodDescriptor().getBareMethodName();
                if (status != Status.OK) {
                    LOGGER.error("Error in processing GRPC call [{0}].[{1}], status: [{2}], ", serviceName, methodName, status);
                } else {
                    LOGGER.info("Call [{0}].[{1}] response message close in [{2}] parts:[\n{3}]", serviceName, methodName, count, messageToPrint);
                }
                super.close(status, trailers);
            }

        };

        // intercept response, log sent message, handle MDC
        return next.startCall(forwardingServerCall, metadata);
    }

    /**
     * Getting defined max logging size value for response
     * 
     * @param 
     *            GRPC request message type
     * @param 
     *            GRPC response message type
     * @param methodDescriptor
     *            Triggered GRPC method on call
     * @return Defined (or not) response body log size. If not defined then {@link LogSpecifier#UNLIMIT}
     */
    protected  int getResponseLogSize(MethodDescriptor methodDescriptor) {
        String serviceName = methodDescriptor.getServiceName();
        String methodName = methodDescriptor.getBareMethodName();
        Class serviceClass;
        try {
            Set> services = CDI.current().getBeanManager().getBeans(Class.forName(serviceName));
            if (services.isEmpty()) {
                return LogSpecifier.UNLIMIT;
            }
            serviceClass = services.iterator().next().getBeanClass();
        } catch (ClassNotFoundException e) {
            LOGGER.debug(MessageFormat.format("Error on getting Request logging size: [{0}]", e.getLocalizedMessage()), e);
            return LogSpecifier.UNLIMIT;
        }
        Optional oMethod = Arrays.stream(serviceClass.getDeclaredMethods()).filter(method -> method.getName().equalsIgnoreCase(methodName))
                .findFirst();
        return ServerRequestInterceptor.getMaxEntityLogSize(oMethod.get(), LogSpecifierTarget.RESPONSE);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy