@@ -471,6 +471,8 @@ Http2Session::Callbacks::Callbacks(bool kHasGetPaddingCallback) {
471
471
callbacks, OnSendData);
472
472
nghttp2_session_callbacks_set_on_invalid_frame_recv_callback (
473
473
callbacks, OnInvalidFrame);
474
+ nghttp2_session_callbacks_set_on_frame_send_callback (
475
+ callbacks, OnFrameSent);
474
476
475
477
if (kHasGetPaddingCallback ) {
476
478
nghttp2_session_callbacks_set_select_padding_callback (
@@ -560,28 +562,35 @@ inline void Http2Stream::EmitStatistics() {
560
562
if (!HasHttp2Observer (env ()))
561
563
return ;
562
564
Http2StreamPerformanceEntry* entry =
563
- new Http2StreamPerformanceEntry (env (), statistics_);
565
+ new Http2StreamPerformanceEntry (env (), id_, statistics_);
564
566
env ()->SetImmediate ([](Environment* env, void * data) {
565
- Local<Context> context = env->context ();
566
567
Http2StreamPerformanceEntry* entry =
567
568
static_cast <Http2StreamPerformanceEntry*>(data);
568
569
if (HasHttp2Observer (env)) {
569
- Local<Object> obj = entry->ToObject ();
570
- v8::PropertyAttribute attr =
571
- static_cast <v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
572
- obj->DefineOwnProperty (
573
- context,
574
- FIXED_ONE_BYTE_STRING (env->isolate (), " timeToFirstByte" ),
575
- Number::New (env->isolate (),
576
- (entry->first_byte () - entry->startTimeNano ()) / 1e6 ),
577
- attr).FromJust ();
578
- obj->DefineOwnProperty (
579
- context,
580
- FIXED_ONE_BYTE_STRING (env->isolate (), " timeToFirstHeader" ),
581
- Number::New (env->isolate (),
582
- (entry->first_header () - entry->startTimeNano ()) / 1e6 ),
583
- attr).FromJust ();
584
- entry->Notify (obj);
570
+ AliasedBuffer<double , v8::Float64Array>& buffer =
571
+ env->http2_state ()->stream_stats_buffer ;
572
+ buffer[IDX_STREAM_STATS_ID] = entry->id ();
573
+ if (entry->first_byte () != 0 ) {
574
+ buffer[IDX_STREAM_STATS_TIMETOFIRSTBYTE] =
575
+ (entry->first_byte () - entry->startTimeNano ()) / 1e6 ;
576
+ } else {
577
+ buffer[IDX_STREAM_STATS_TIMETOFIRSTBYTE] = 0 ;
578
+ }
579
+ if (entry->first_header () != 0 ) {
580
+ buffer[IDX_STREAM_STATS_TIMETOFIRSTHEADER] =
581
+ (entry->first_header () - entry->startTimeNano ()) / 1e6 ;
582
+ } else {
583
+ buffer[IDX_STREAM_STATS_TIMETOFIRSTHEADER] = 0 ;
584
+ }
585
+ if (entry->first_byte_sent () != 0 ) {
586
+ buffer[IDX_STREAM_STATS_TIMETOFIRSTBYTESENT] =
587
+ (entry->first_byte_sent () - entry->startTimeNano ()) / 1e6 ;
588
+ } else {
589
+ buffer[IDX_STREAM_STATS_TIMETOFIRSTBYTESENT] = 0 ;
590
+ }
591
+ buffer[IDX_STREAM_STATS_SENTBYTES] = entry->sent_bytes ();
592
+ buffer[IDX_STREAM_STATS_RECEIVEDBYTES] = entry->received_bytes ();
593
+ entry->Notify (entry->ToObject ());
585
594
}
586
595
delete entry;
587
596
}, static_cast <void *>(entry));
@@ -591,45 +600,25 @@ inline void Http2Session::EmitStatistics() {
591
600
if (!HasHttp2Observer (env ()))
592
601
return ;
593
602
Http2SessionPerformanceEntry* entry =
594
- new Http2SessionPerformanceEntry (env (), statistics_, TypeName () );
603
+ new Http2SessionPerformanceEntry (env (), statistics_, session_type_ );
595
604
env ()->SetImmediate ([](Environment* env, void * data) {
596
- Local<Context> context = env->context ();
597
605
Http2SessionPerformanceEntry* entry =
598
606
static_cast <Http2SessionPerformanceEntry*>(data);
599
607
if (HasHttp2Observer (env)) {
600
- Local<Object> obj = entry->ToObject ();
601
- v8::PropertyAttribute attr =
602
- static_cast <v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
603
- obj->DefineOwnProperty (
604
- context,
605
- FIXED_ONE_BYTE_STRING (env->isolate (), " type" ),
606
- String::NewFromUtf8 (env->isolate (),
607
- entry->typeName (),
608
- v8::NewStringType::kInternalized )
609
- .ToLocalChecked (), attr).FromJust ();
610
- if (entry->ping_rtt () != 0 ) {
611
- obj->DefineOwnProperty (
612
- context,
613
- FIXED_ONE_BYTE_STRING (env->isolate (), " pingRTT" ),
614
- Number::New (env->isolate (), entry->ping_rtt () / 1e6 ),
615
- attr).FromJust ();
616
- }
617
- obj->DefineOwnProperty (
618
- context,
619
- FIXED_ONE_BYTE_STRING (env->isolate (), " framesReceived" ),
620
- Integer::NewFromUnsigned (env->isolate (), entry->frame_count ()),
621
- attr).FromJust ();
622
- obj->DefineOwnProperty (
623
- context,
624
- FIXED_ONE_BYTE_STRING (env->isolate (), " streamCount" ),
625
- Integer::New (env->isolate (), entry->stream_count ()),
626
- attr).FromJust ();
627
- obj->DefineOwnProperty (
628
- context,
629
- FIXED_ONE_BYTE_STRING (env->isolate (), " streamAverageDuration" ),
630
- Number::New (env->isolate (), entry->stream_average_duration ()),
631
- attr).FromJust ();
632
- entry->Notify (obj);
608
+ AliasedBuffer<double , v8::Float64Array>& buffer =
609
+ env->http2_state ()->session_stats_buffer ;
610
+ buffer[IDX_SESSION_STATS_TYPE] = entry->type ();
611
+ buffer[IDX_SESSION_STATS_PINGRTT] = entry->ping_rtt () / 1e6 ;
612
+ buffer[IDX_SESSION_STATS_FRAMESRECEIVED] = entry->frame_count ();
613
+ buffer[IDX_SESSION_STATS_FRAMESSENT] = entry->frame_sent ();
614
+ buffer[IDX_SESSION_STATS_STREAMCOUNT] = entry->stream_count ();
615
+ buffer[IDX_SESSION_STATS_STREAMAVERAGEDURATION] =
616
+ entry->stream_average_duration ();
617
+ buffer[IDX_SESSION_STATS_DATA_SENT] = entry->data_sent ();
618
+ buffer[IDX_SESSION_STATS_DATA_RECEIVED] = entry->data_received ();
619
+ buffer[IDX_SESSION_STATS_MAX_CONCURRENT_STREAMS] =
620
+ entry->max_concurrent_streams ();
621
+ entry->Notify (entry->ToObject ());
633
622
}
634
623
delete entry;
635
624
}, static_cast <void *>(entry));
@@ -695,6 +684,9 @@ inline bool Http2Session::CanAddStream() {
695
684
inline void Http2Session::AddStream (Http2Stream* stream) {
696
685
CHECK_GE (++statistics_.stream_count , 0 );
697
686
streams_[stream->id ()] = stream;
687
+ size_t size = streams_.size ();
688
+ if (size > statistics_.max_concurrent_streams )
689
+ statistics_.max_concurrent_streams = size;
698
690
IncrementCurrentSessionMemory (stream->self_size ());
699
691
}
700
692
@@ -963,6 +955,14 @@ inline int Http2Session::OnFrameNotSent(nghttp2_session* handle,
963
955
return 0 ;
964
956
}
965
957
958
+ inline int Http2Session::OnFrameSent (nghttp2_session* handle,
959
+ const nghttp2_frame* frame,
960
+ void * user_data) {
961
+ Http2Session* session = static_cast <Http2Session*>(user_data);
962
+ session->statistics_ .frame_sent += 1 ;
963
+ return 0 ;
964
+ }
965
+
966
966
// Called by nghttp2 when a stream closes.
967
967
inline int Http2Session::OnStreamClose (nghttp2_session* handle,
968
968
int32_t id,
@@ -1040,6 +1040,7 @@ inline int Http2Session::OnDataChunkReceived(nghttp2_session* handle,
1040
1040
// If the stream has been destroyed, ignore this chunk
1041
1041
if (stream->IsDestroyed ())
1042
1042
return 0 ;
1043
+ stream->statistics_ .received_bytes += len;
1043
1044
stream->AddChunk (data, len);
1044
1045
}
1045
1046
return 0 ;
@@ -1494,6 +1495,7 @@ void Http2Session::SendPendingData() {
1494
1495
size_t offset = 0 ;
1495
1496
size_t i = 0 ;
1496
1497
for (const nghttp2_stream_write& write : outgoing_buffers_) {
1498
+ statistics_.data_sent += write .buf .len ;
1497
1499
if (write .buf .base == nullptr ) {
1498
1500
bufs[i++] = uv_buf_init (
1499
1501
reinterpret_cast <char *>(outgoing_storage_.data () + offset),
@@ -1643,6 +1645,7 @@ void Http2Session::OnStreamReadImpl(ssize_t nread,
1643
1645
if (bufs->len > 0 ) {
1644
1646
// Only pass data on if nread > 0
1645
1647
uv_buf_t buf[] { uv_buf_init ((*bufs).base , nread) };
1648
+ session->statistics_ .data_received += nread;
1646
1649
ssize_t ret = session->Write (buf, 1 );
1647
1650
1648
1651
// Note: if ssize_t is not defined (e.g. on Win32), nghttp2 will typedef
@@ -2142,6 +2145,8 @@ ssize_t Http2Stream::Provider::FD::OnRead(nghttp2_session* handle,
2142
2145
void * user_data) {
2143
2146
Http2Session* session = static_cast <Http2Session*>(user_data);
2144
2147
Http2Stream* stream = session->FindStream (id);
2148
+ if (stream->statistics_ .first_byte_sent == 0 )
2149
+ stream->statistics_ .first_byte_sent = uv_hrtime ();
2145
2150
2146
2151
DEBUG_HTTP2SESSION2 (session, " reading outbound file data for stream %d" , id);
2147
2152
CHECK_EQ (id, stream->id ());
@@ -2192,6 +2197,7 @@ ssize_t Http2Stream::Provider::FD::OnRead(nghttp2_session* handle,
2192
2197
return NGHTTP2_ERR_CALLBACK_FAILURE;
2193
2198
}
2194
2199
2200
+ stream->statistics_ .sent_bytes += numchars;
2195
2201
return numchars;
2196
2202
}
2197
2203
@@ -2217,6 +2223,8 @@ ssize_t Http2Stream::Provider::Stream::OnRead(nghttp2_session* handle,
2217
2223
Http2Session* session = static_cast <Http2Session*>(user_data);
2218
2224
DEBUG_HTTP2SESSION2 (session, " reading outbound data for stream %d" , id);
2219
2225
Http2Stream* stream = GetStream (session, id, source);
2226
+ if (stream->statistics_ .first_byte_sent == 0 )
2227
+ stream->statistics_ .first_byte_sent = uv_hrtime ();
2220
2228
CHECK_EQ (id, stream->id ());
2221
2229
2222
2230
size_t amount = 0 ; // amount of data being sent in this data frame.
@@ -2250,6 +2258,8 @@ ssize_t Http2Stream::Provider::Stream::OnRead(nghttp2_session* handle,
2250
2258
if (session->IsDestroyed ())
2251
2259
return NGHTTP2_ERR_CALLBACK_FAILURE;
2252
2260
}
2261
+
2262
+ stream->statistics_ .sent_bytes += amount;
2253
2263
return amount;
2254
2264
}
2255
2265
@@ -2863,6 +2873,10 @@ void Initialize(Local<Object> target,
2863
2873
" settingsBuffer" , state->settings_buffer .GetJSArray ());
2864
2874
SET_STATE_TYPEDARRAY (
2865
2875
" optionsBuffer" , state->options_buffer .GetJSArray ());
2876
+ SET_STATE_TYPEDARRAY (
2877
+ " streamStats" , state->stream_stats_buffer .GetJSArray ());
2878
+ SET_STATE_TYPEDARRAY (
2879
+ " sessionStats" , state->session_stats_buffer .GetJSArray ());
2866
2880
#undef SET_STATE_TYPEDARRAY
2867
2881
2868
2882
env->set_http2_state (std::move (state));
0 commit comments