summaryrefslogtreecommitdiffstats
path: root/src/grpc/doc/src/qtgrpcclientinterceptor-logging.qdoc
blob: 45ab2a2b2340863de3196d391e7d585e30dfdd0c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only

/*!
\page qtgrpcclientinterceptor-logging.html
\ingroup qtgrpc-client-interceptor
\title QGrpcClientInterceptor logging example

\section1 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.

\section1 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.

\section2 Prerequisites
To establish what types can be processed by our interceptor,
let's say our .proto file is:
\badcode
syntax = "proto3";

message SimpleStringMessage {
    string testFieldString = 6;
}

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

\section2 LoggingInterceptor implementation

Here's an example of a simple Logging Interceptor:
\code
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);
    }
};
\endcode

The LoggingInterceptor overrides two interception methods:
\l{QGrpcClientInterceptor::interceptCall} and
\l{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
\c qDebug().

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

\section1 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.
\code
QGrpcClientInterceptorManager manager;
std::shared_ptr<LoggingInterceptor> loggingInterceptor = std::make_shared<LoggingInterceptor>();
manager.registerInterceptor(loggingInterceptor);
\endcode
*/