Uh oh!
There was an error while loading. Please reload this page.
Improve the pretty print for operator<<Frame, operator<<Payload - #504
Conversation
| ss << delimeter << "FOLLOWS"; | ||
| if (!!(allowedFlags & FrameFlags::RESUME_ENABLE) | ||
| && !!(frameFlags & FrameFlags::RESUME_ENABLE)) { | ||
| ss << delimeter << "RESUEN"; |
There was a problem hiding this comment.
might be a typo RESUEN ->RESUME?
| } | ||
| if (!!(allowedFlags & FrameFlags::COMPLETE) | ||
| && !!(frameFlags & FrameFlags::COMPLETE)) { // COMPLETE = 0x40 | ||
| ss << delimeter << "COMPLE"; |
There was a problem hiding this comment.
I was trying to use short version of these enum values. Let me use the whole word version of them. Seems like it will be problem in the future if I use the short versions.
| std::string delimeter = ""; | ||
| if (!!(frameFlags & FrameFlags::NEXT)) { | ||
| ss << "NEXT"; | ||
| if (!!(allowedFlags & FrameFlags::IGNORE) |
There was a problem hiding this comment.
Would it be possible to loop over these flags instead of all the if statements?
You can use the to_string function to print out the flags.
phoad
commented
Jun 8, 2017
Previous commit (in this CR) was printing out multiple values, instead of a single one for FrameFlags' value of 80 / 40.. (Thanks for catching it Scott) enum clas.. { Before: As seen KEEPALIVE_RESPOND is the only Flag for Frame_KEEPALIVE, but as it's value was matching with the RESUME_ENABLE, KEEPALIVE_RESPOND and FOLLOW, previous version of this PR was writing all of them. This update fixed it. Out: PAYLOAD[NEXT|METADATA, 1], ([Metadata(8): 'metadata', Data(13): 'Hello Jane 1!'] |
ragansa
left a comment
There was a problem hiding this comment.
Looks good to me!
Would it be more manageable if we had the frames implement a common interface and could just have the one std::ostream& operator<<(), and have each frame print out it's own flags?
| return os << frame.header_ << ", " << frame.payload_; | ||
| static const std::vector<std::pair<FrameFlags, std::string>> allowedFlags { | ||
| {FrameFlags::METADATA, sFrameFlags_METADATA}, | ||
| {FrameFlags::FOLLOWS, sFrameFlags_FOLLOWS} }; |
There was a problem hiding this comment.
Any reason why we are not using the AllowedFlags member variable of the Frame struct (instead of redefining it here) ? Then you could write a simple utility function which takes a list of FrameFlags and returns a string (or vector of strings).
std::ostream& operator<<(std::ostream& os, const Frame_REQUEST_RESPONSE& frame) {
return os << frame.header_ << ", " << frame.payload_ << toString(frame.AllowedFlags);
}
There was a problem hiding this comment.
I think the problem is that the AllowedFlags doesn't tell you which actual flags that frame can have. Just what values of flags that the frame can have. (There is overlap in flag values)
i.e. An AllowedFlags values tells you that the frame can have a flag of value 0x80 but doesn't specify if that means RESUME_ENABLE, KEEPALIVE_RESPOND, or FOLLOWS
There was a problem hiding this comment.
Even though the FrameFlags is an enum class, it is used as old C/++ way and OR/AND operations are applied on it to get a bitset, that represents a set of flags. Furthermore, this enum has members which has the same int value. So to be able to differentiate between what's the corresponding Flag enum member for the given int value, we need information from the Frame type. It is not possible to apply switch/case on them.
We write the "flags" when we write the "header". So the information about the flags is existing in the "header" data member. So, this line will not provide the desired result. return os << frame.header_ << ", " << frame.payload_ << toString(frame.AllowedFlags);
We have a set of flags that are accepted by each Frame type. We should match these flags with the given flag values in the "header.flags". If the frame accepts RESUME_ENABLE, and if the given flag value is 0x80, we should only match with RESUME_ENABLE, but not with KEEPALIVE_RESPOND or FOLLOWS. For this we need to pass information about the frame along with the header to "operator<<" function.
I have tried to do no change in the declaration of the Frame classes and do all the updates in the cpp code.
| : "0") | ||
| << (payload.metadata | ||
| ? "): '" + payload.metadata->cloneAsValue().moveToFbString().substr(0, 80).toStdString() + "'" | ||
| ? "): '" + payload.metadata->cloneAsValue().moveToFbString().substr(0, 40).toStdString() + "'" |
| std::ostream& operator<<(std::ostream& os, FrameFlags frameFlags) { | ||
| // TODO Match the Flag names with the AllowedFlags in the Frame declarations | ||
| constexpr const char sFrameFlags_EMPTY[] = "EMPTY"; |
There was a problem hiding this comment.
nit. EMPTY can be interpreted as a flag. I would not print any flag.
There was a problem hiding this comment.
Yes, you are right. Let me write the 0x00, to state that the flags are empty!
phoad
commented
Jun 13, 2017
@alexmalyshev can you take a look to this PR and merge it? |
| std::ostream& operator<<(std::ostream& os, FrameFlags frameFlags) { | ||
| // TODO Match the Flag names with the AllowedFlags in the Frame declarations | ||
| constexpr const char sFrameFlags_EMPTY[] = "0x00"; |
There was a problem hiding this comment.
These should be const char*. Normally char[] is reserved for mutable character buffers.
| constexpr const char sFrameFlags_KEEPALIVE_RESPOND[] = "KEEPALIVE_RESPOND"; | ||
| constexpr const char sFrameFlags_FOLLOWS[] = "FOLLOWS"; | ||
| constexpr const char sFrameFlags_COMPLETE[] = "COMPLETE"; | ||
| constexpr const char sFrameFlags_NEXT[] = "NEXT"; |
There was a problem hiding this comment.
I wouldn't name these sFrameFlags_NEXT. The convention for string literals is kStringLiteralName, and I think we can get away with doing kNext instead of duplicating the sFrameFlags prefix everywhere.
| std::ostream& os, | ||
| const std::pair< | ||
| const FrameHeader&, | ||
| const std::vector<std::pair<FrameFlags, std::string>>&>& |
There was a problem hiding this comment.
This is really rough to understand... The second element in this pair is a vector<pair<Flags, std::string>>& which is also inside a wrapping pair<...,...>&. All for the purpose of fitting everything into a single argument for operator<<.
There's no need to use vectors to track which flags are allowed for which frame header. You can write a FrameFlags allowedFlags(FrameType); function and that can use the type in the header. Then have a const char* toString(FrameFlags, FrameType); that'll decide which string to return (need the type to differentiate between flags like FOLLOWS and KEEPALIVE_RESPOND).
I think instead of writingstd::ostream& operator<<(std::ostream&, const std::vector<std::pair<FrameFlags, std::string>>&>&);
I think we can do everything we want withstd::ostream& operator<<(std::ostream&, const FrameHeader&);
There was a problem hiding this comment.
Good suggestion. I have also noticed today that we have a matching FrameType per Frame class type. Now its easier to do the thing.
There was a problem hiding this comment.
I do not need the FrameFlags information of the Frame class types. Though I need a mapping between each flag type to corresponding string value per Frame class type. I prepared a map for this. I am open for suggestion, though it seemed required such a map to me.
| if(APPLE) | ||
| set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl") | ||
| set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl;/usr/local/homebrew/opt/openssl") |
There was a problem hiding this comment.
Should this be part of this PR?
There was a problem hiding this comment.
I needed it to build in my box, though it does not need to be here.
| std::ostream& operator<<(std::ostream& os, FrameFlags frameFlags) { | ||
| // TODO Match the Flag names with the AllowedFlags in the Frame declarations | ||
| std::ostream& operator<<(std::ostream& os, std::pair<FrameFlags, FrameType> frameFlagsAndType) { |
There was a problem hiding this comment.
I still think it's better to make this a function instead of an operator<< overload, i.e. std::ostream& writeFlags(std::ostream&, FrameType, FrameFlags);. Having to make a pair just to pass in two arguments is silly.
There was a problem hiding this comment.
Sure. I thought if we write a function we will not be able to write
os << x << y << z;
Let me update the code accordingly.
yschimke
commented
Jun 20, 2017
@fuat this seems like it might be annoying for terminal output when payloads contain binary. Have you considered hex formatting or filtering unprintable characters? |
@yschimke I will use folly::humanify functionality. Would you like me to print all the data or should I still use substr? @534 /**
|
Improve the pretty print code to match the Flag name with the AllowedFlags data member in the Frame classes.
Sample output:
I0606 16:14:25.145932 237998080 RSocketStateMachine.h:144] Out: PAYLOAD[METADANEXT, 1], ([Metadata(8): 'metadata', Data(13): 'Hello Jane 1!']
I0606 16:14:25.146798 237998080 RSocketStateMachine.h:144] Out: PAYLOAD[METADANEXT, 1], ([Metadata(8): 'metadata', Data(14): 'Hello Jane 10!']
I0606 16:14:25.146890 237998080 RSocketStateMachine.h:144] Out: PAYLOAD[LEASE|COMPLE, 1], ([Metadata(0): , Data(0): ]
I0606 16:14:30.147658 237998080 RSocketStateMachine.cpp:445] In: KEEPALIVERESUEN|KALIVR|FOLLOW, 0
I0606 16:14:30.147709 237998080 RSocketStateMachine.cpp:699] Out: KEEPALIVEEMPTY, 0