fishy edited a comment on pull request #1992:
URL: https://github.com/apache/thrift/pull/1992#issuecomment-705903922
Since the only gap between interceptor idea and already existing middleware
are the requests/responses, here's an idea to add that ability, without any
compiler changes (this can even be from a third party library, it doesn't use
any unexported function from the thrift library).
First you just need to implement a `RecordingTProtocol` (name TBD, it can
also be `InterceptorTProtocol` if you like):
```go
type RecordingTProtocol struct {
Recording, Actual TProtocol
}
func (rp RecordingTProtocol) ReadMessageBegin() (name string, typeId
TMessageType, seqid int32, err error) {
name, typeId, seqid, err = rp.Actual.ReadMessageBegin()
if err != nil {
err = rp.Recording.WriteMessageBegin(name, typeId, seqid)
}
}
// TODO: implement other TProtocol read functions
func (rp RecordingTProtocol) WriteMessageBegin(name string, typeId
TMessageType, seqid int32) (err error) {
rp.Recording.WriteMessageBegin(name, typeId, seqid)
err = rp.Actual.WriteMessageBegin(name, typeId, seqid)
}
// TODO: implement other TProtocol write functions
```
Then you can just use it in a middleware implementation and combine it with
`TMemoryBuffer` as the underlying `TTransport` for the recording one. For
example for json logging:
```go
var pool = sync.Pool{
New: func() interface{} {
return thrift.NewTMemoryBuffer()
},
}
func loggingMiddleware(name string, next thrift.TProcessorFunction)
thrift.TProcessorFunction {
return thrift.WrappedTProcessorFunction{
Wrapped: func(ctx context.Context, seqID int32, in, out
thrift.TProtocol) (_ bool, err thrift.TException) {
inBuf := pool.Get().(*thrift.TMemoryBuffer)
inBuf.Reset()
iproto := thrift.NewTSimpleJSONProtocol(inBuf)
// Since in thrift compiled Processor functions, we call
ReadMessageBegin
// before calling the actual processor, we will have the
ReadMessageEnd at
// the end without the pairing ReadMessageBegin call, and that will
cause
// TSimpleJSONProtocol to panic.
iproto.WriteMessageBegin(ctx, "" /* name */, thrift.CALL, seqID)
in = TRecordingProtocol{
Actual: in,
Recording: iproto,
}
outBuf := pool.Get().(*thrift.TMemoryBuffer)
outBuf.Reset()
oproto := thrift.NewTSimpleJSONProtocol(outBuf)
out = TRecordingProtocol{
Actual: out,
Recording: oproto,
}
defer func() {
iproto.Flush(ctx)
logger("method", name, "request", inBuf.String(), "response",
outBuf.String(), "err", err)
}()
return next.Process(ctx, seqID, in, out)
},
}
}
```
And I can also use it to record the size on the wire (also I think this is
inefficient and it's better done in envoy/etc.):
```go
func sizeRecordingMiddleware(name string, next thrift.TProcessorFunction)
thrift.TProcessorFunction {
return thrift.WrappedTProcessorFunction{
Wrapped: func(ctx context.Context, seqID int32, in, out
thrift.TProtocol) (bool, thrift.TException) {
inBuf := pool.Get().(*thrift.TMemoryBuffer)
inBuf.Reset()
outBuf := pool.Get().(*thrift.TMemoryBuffer)
outBuf.Reset()
defer func() {
requestSizeHistogram.Observe(inBuf.Len())
responseSizeHistogram.Observe(outBuf.Len())
pool.Put(inBuf)
pool.Put(outBuf)
}()
iproto := factory.GetProtocol(inBuf)
in = TRecordingProtocol{
Actual: in,
Recording: iproto,
}
oproto := factory.GetProtocol(outBuf)
out = TRecordingProtocol{
Actual: out,
Recording: oproto,
}
return next.Process(ctx, seqID, in, out)
},
}
}
```
If people find it useful I can totally just implement this
`RecordingTProtocol` in thrift library.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]