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