QGrpcClientInterceptor logging example

Logging Interceptor

The Logging Interceptor can be a versatile tool for gaining insights into your Qt GRPC requests. By creating a custom interceptor, you can tailor the logging behavior to meet the specific requirements of your application.

Creating a Logging Interceptor

To create a Logging Interceptor, you'll need to subclass QGrpcClientInterceptor and override the appropriate interception method(s) to incorporate the logging functionality.

Prerequisites

To establish what types can be processed by our interceptor, let's say our .proto file is:

syntax = "proto3";

message SimpleStringMessage {
    string testFieldString = 6;
}

service TestService {
    rpc testMethod(SimpleStringMessage) returns (SimpleStringMessage) {}
    rpc testMethodServerStream(SimpleStringMessage) returns (stream SimpleStringMessage) {}
}

LoggingInterceptor implementation

Here's an example of a simple Logging Interceptor:

class LoggingInterceptor : public QGrpcClientInterceptor
{
protected:
    void interceptCall(std::shared_ptr<QGrpcChannelOperation> operation,
                                                  std::shared_ptr<QGrpcCallReply> response,
                                                  QGrpcInterceptorContinuation<QGrpcCallReply> &continuation) override
    {
        // Log an outgoing requests here
        SimpleStringMessage requestArg;
        if (!operation->serializer()->deserialize(&requestArg, operation->arg())) {
            qError() << "Deserialization of arg failed.";
            return;
        }
        qDebug() << "Request sent:" << requestArg.testFieldString();

        continuation(std::move(response), operation);

        // Intercept the response
        auto responsePtr = response.get();
        QObject::connect(responsePtr, &QGrpcServerStream::messageReceived, responsePtr,
                        [responsePtr]{
                            const auto mess = responsePtr->read<SimpleStringMessage>();
                            if (!mess)
                                qDebug() << "Failed deserialization";
                            qDebug() << "Response received:" << mess->testFieldString();
                        });
    }

    void interceptServerStream(std::shared_ptr<QGrpcChannelOperation> operation,
                                                  std::shared_ptr<QGrpcServerStream> stream,
                                                  QGrpcInterceptorContinuation<QGrpcServerStream> &continuation) override
    {
        // Intercept the response
        QObject::connect(stream.get(), &QGrpcServerStream::messageReceived, this,
                             [stream] {
                                if (const auto mess = responsePtr->read<SimpleStringMessage>())
                                    qDebug() << "Response received:" << mess->testFieldString();
                             });

        // Log incoming and outgoing requests here
        SimpleStringMessage requestArg;
        if (!operation->serializer()->deserialize(&requestArg, operation->arg())) {
            qError() << "Deserialization of arg failed.";
            return;
        }
        qDebug() << "Request sent:" << requestArg.testFieldString();
        continuation(std::move(response), operation);
    }
};

The LoggingInterceptor overrides two interception methods: QGrpcClientInterceptor::interceptCall and QGrpcClientInterceptor::interceptServerStream. Each of these methods handles a specific type of Qt GRPC interaction: Unary call and server streaming, respectively. Because QGrpcChannelOperation stores the argument in the serialized form, both methods need to deserialize the request, which can then be logged using qDebug().

Use QObject::connect to subscribe to the QGrpcCallReply::finished or QGrpcServerStream::messageReceived signals and log the response.

Registering the Logging Interceptor

Next, you'll need to register the Logging Interceptor with the QGrpcClientInterceptorManager. This ensures that it becomes part of the interceptor chain.

QGrpcClientInterceptorManager manager;
std::shared_ptr<LoggingInterceptor> loggingInterceptor = std::make_shared<LoggingInterceptor>();
manager.registerInterceptor(loggingInterceptor);

© 2024 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.