-
Notifications
You must be signed in to change notification settings - Fork 134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support NATS #270
base: main
Are you sure you want to change the base?
feat: support NATS #270
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
@hengyoush All the tests are stuck in
|
if !ok1 || !ok2 { | ||
return []protocol.Record{} | ||
} | ||
return protocol.MatchByTimestamp(reqStream, respStream) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the NATS protocol, not all requests necessarily have responses (https://docs.nats.io/reference/reference-protocols/nats-protocol#ok-err). Is it possible that solely using MatchByTimestamp might result in losing records?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you are right. Only [H]PUB or [H]MSG with reply-to
and PING/PONG are matching request/response. Both NATS server and client could start with PING, I'm not sure it's possible to distinguish which side starts with PING.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure it's possible to distinguish which side starts with PING.
I wonder if it is really necessary to distinguish which side initiated the ping. For ping/pong, can we match them using the MatchByTimestamp logic?
For other types of messages, we can traverse both respStream and reqStream simultaneously. If the respMessage is ok/err, then it forms a record with the reqMessage.
If the respMessage is not ok/err, then we need to output a record based on the timestamps of the current reqMessage and respMessage. If reqMessage.Ts < respMessage.Ts, output a record with only the req (resp is empty); otherwise, output a record with only the resp.
} | ||
|
||
func (parser *NatsStreamParser) FindBoundary(streamBuffer *buffer.StreamBuffer, messageType protocol.MessageType, startPos int) int { | ||
return 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can determine the boundary based on the message type (nats protocol messages) (actually what you did in protocol_inference.h)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, I will fix this
} | ||
} | ||
offset := index - len(method) | ||
msg, prasedLen := natsParser.Parse(buffer[offset:], messageType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo here: prasedLen => parsedLen
if packetLen < 0 { | ||
return nil, -1 | ||
} | ||
parts := splitFields(payload[:packetLen-len(_CRLF_)]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to check slice bound here?(len(payload) < packetLen-len(_CRLF_)
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's no necessary. packetLen
means the first line length in payload
(if contains \r\n
), len(payload) >= packetLen
always true.
@@ -127,6 +127,141 @@ static __always_inline enum message_type_t is_http_protocol(const char *old_buf, | |||
return kUnknown; | |||
} | |||
|
|||
static __always_inline bool is_nats_info(const char *old_buf, size_t count) { | |||
if (count < 6) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this check for less than 6 redundant, since 20 bytes will be read below?
} | ||
|
||
static __always_inline bool is_nats_connect(const char *old_buf, size_t count) { | ||
if (count < 8) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also here
bpf_probe_read_user(buf, 20, old_buf); | ||
|
||
#pragma unroll | ||
for (size_t p = 5; p < 20; p++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this loop check be omitted? If so, we can determine nats message type with just one bpf_probe_read_user call to reduce the num of instructions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure is other protocols start whit INFO
or CONNECT
as NATS did, if not I think this loop can be omitted.
Indeed, this need to be fixed with adding a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I TBI k I could continue but it's a good start
"kyanos/agent/protocol" | ||
"kyanos/bpf" | ||
"kyanos/common" | ||
"slices" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"kyanos/agent/protocol" | |
"kyanos/bpf" | |
"kyanos/common" | |
"slices" | |
"slices" | |
"kyanos/agent/protocol" | |
"kyanos/bpf" | |
"kyanos/common" |
import ( | ||
"bytes" | ||
"encoding/json" | ||
"fmt" | ||
"kyanos/agent/buffer" | ||
"kyanos/agent/protocol" | ||
"kyanos/bpf" | ||
"kyanos/common" | ||
"strconv" | ||
"strings" | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please fix import orders
) | ||
|
||
const ( | ||
_CRLF_ = "\r\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't use uppercase constant in Go
if msg.ProtocolCode == PING || msg.ProtocolCode == PONG { | ||
return 1 | ||
} | ||
return 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be a switch
// if strings.ToUpper(string(parts[0])) != "INFO" { | ||
// return nil, packetLen | ||
// } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented code is always suspicious.
Either it could have been removed, or something was temporarily commented for debug and it was left commented while it shouldn't
|
||
func (m *Hmsg) Parse(payload []byte, messageType protocol.MessageType) (*NatsMessage, int) { | ||
common.ProtocolParserLog.Debugf("NATS Parse Hmsg:%d, %x", len(payload), string(payload)) | ||
msg, prasedLen := m.ParseData(payload) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
parsedLen
// if !strings.HasPrefix(strings.ToUpper(string(payload[:4])), "PING") { | ||
// return nil, packetLen | ||
// } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again
} | ||
|
||
func init() { | ||
natsCmd.Flags().StringSlice("protocols", []string{}, "Specify the nats protocol to monitor(PUB, SUB, MSG), seperate by ','") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
natsCmd.Flags().StringSlice("protocols", []string{}, "Specify the nats protocol to monitor(PUB, SUB, MSG), seperate by ','") | |
natsCmd.Flags().StringSlice("protocols", []string{}, "Specify the NATS protocol to monitor (PUB, SUB, MSG), seperate by ','") |
|
||
func init() { | ||
natsCmd.Flags().StringSlice("protocols", []string{}, "Specify the nats protocol to monitor(PUB, SUB, MSG), seperate by ','") | ||
natsCmd.Flags().StringSlice("subjects", []string{}, "Specify the nats subject to monitor, seperate by ','") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
natsCmd.Flags().StringSlice("subjects", []string{}, "Specify the nats subject to monitor, seperate by ','") | |
natsCmd.Flags().StringSlice("subjects", []string{}, "Specify the NATS subject to monitor, seperate by ','") |
interval := flag.Duration("interval", 5*time.Second, "Interval between messages") | ||
flag.Parse() | ||
|
||
// 连接到NATS服务器 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use plain English comments
This will close #206