diff --git a/trunk/src/app/srs_app_rtc_server.cpp b/trunk/src/app/srs_app_rtc_server.cpp index 67698172f..1a8c9dbf7 100644 --- a/trunk/src/app/srs_app_rtc_server.cpp +++ b/trunk/src/app/srs_app_rtc_server.cpp @@ -675,6 +675,9 @@ srs_error_t SrsRtcServer::notify(int type, srs_utime_t interval, srs_utime_t tic return err; } + // Show udp snmp statistic for RTC server. + SrsSnmpUdpStat* s = srs_get_udp_snmp_stat(); + // Update the pps stat for UDP socket and adddresses. _srs_pps_rpkts->update(); _srs_pps_rrtps->update(); _srs_pps_rstuns->update(); _srs_pps_rrtcps->update(); _srs_pps_spkts->update(); _srs_pps_srtps->update(); _srs_pps_sstuns->update(); _srs_pps_srtcps->update(); @@ -684,13 +687,14 @@ srs_error_t SrsRtcServer::notify(int type, srs_utime_t interval, srs_utime_t tic _srs_pps_ids->update(); _srs_pps_fids->update(); _srs_pps_fids_level0->update(); _srs_pps_addrs->update(); _srs_pps_fast_addrs->update(); // TODO: FIXME: Show more data for RTC server. - srs_trace("RTC: Server conns=%u, rpkts=%d,%d,%d,%d, spkts=%d,%d,%d,%d, rtcp=%d,%d,%d, snk=%d,%d,%d,%d, rnk=%d,%d,%d,%d, fid=%d,%d,%d,%d,%d", + srs_trace("RTC: Server conns=%u, rpkts=%d,%d,%d,%d, spkts=%d,%d,%d,%d, rtcp=%d,%d,%d, snk=%d,%d,%d,%d, rnk=%d,%d,%d,%d, drop=%d,%d, fid=%d,%d,%d,%d,%d", nn_rtc_conns, _srs_pps_rpkts->r10s(), _srs_pps_rrtps->r10s(), _srs_pps_rstuns->r10s(), _srs_pps_rrtcps->r10s(), _srs_pps_spkts->r10s(), _srs_pps_srtps->r10s(), _srs_pps_sstuns->r10s(), _srs_pps_srtcps->r10s(), _srs_pps_pli->r10s(), _srs_pps_twcc->r10s(), _srs_pps_rr->r10s(), _srs_pps_snack->r10s(), _srs_pps_sanack->r10s(), _srs_pps_svnack->r10s(), _srs_pps_snack2->r10s(), _srs_pps_rnack->r10s(), _srs_pps_rnack2->r10s(), _srs_pps_rhnack->r10s(), _srs_pps_rmnack->r10s(), + s->rcv_buf_errors_delta, s->snd_buf_errors_delta, _srs_pps_ids->r10s(), _srs_pps_fids->r10s(), _srs_pps_fids_level0->r10s(), _srs_pps_addrs->r10s(), _srs_pps_fast_addrs->r10s() ); diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 563328555..99d76df1e 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -1280,6 +1280,10 @@ srs_error_t SrsServer::setup_ticks() if ((err = timer_->tick(8, 3 * SRS_UTIME_SECONDS)) != srs_success) { return srs_error_wrap(err, "tick"); } + + if ((err = timer_->tick(10, 9 * SRS_UTIME_SECONDS)) != srs_success) { + return srs_error_wrap(err, "tick"); + } } if (_srs_config->get_heartbeat_enabled()) { @@ -1308,6 +1312,7 @@ srs_error_t SrsServer::notify(int event, srs_utime_t interval, srs_utime_t tick) case 7: srs_update_network_devices(); break; case 8: resample_kbps(); break; case 9: http_heartbeat->heartbeat(); break; + case 10: srs_update_udp_snmp_statistic(); break; } return err; diff --git a/trunk/src/app/srs_app_utility.cpp b/trunk/src/app/srs_app_utility.cpp index bde16dc83..a7251cf22 100644 --- a/trunk/src/app/srs_app_utility.cpp +++ b/trunk/src/app/srs_app_utility.cpp @@ -851,6 +851,94 @@ void srs_update_platform_info() r.ok = true; } +SrsSnmpUdpStat::SrsSnmpUdpStat() +{ + ok = false; + + in_datagrams = 0; + no_ports = 0; + in_errors = 0; + out_datagrams = 0; + rcv_buf_errors = 0; + snd_buf_errors = 0; + in_csum_errors = 0; + + rcv_buf_errors_delta = 0; + snd_buf_errors_delta = 0; +} + +SrsSnmpUdpStat::~SrsSnmpUdpStat() +{ +} + +static SrsSnmpUdpStat _srs_snmp_udp_stat; + +bool get_udp_snmp_statistic(SrsSnmpUdpStat& r) +{ +#ifndef SRS_OSX + if (true) { + FILE* f = fopen("/proc/net/snmp", "r"); + if (f == NULL) { + srs_warn("open proc network snmp failed, ignore"); + return false; + } + + // ignore title. + static char buf[1024]; + fgets(buf, sizeof(buf), f); + + while (fgets(buf, sizeof(buf), f)) { + // udp stat title + if (strncmp(buf, "Udp: ", 5) == 0) { + // read tcp stat data + if (!fgets(buf, sizeof(buf), f)) { + break; + } + // parse tcp stat data + if (strncmp(buf, "Udp: ", 5) == 0) { + sscanf(buf + 5, "%llu %llu %llu %llu %llu %llu %llu\n", + &r.in_datagrams, + &r.no_ports, + &r.in_errors, + &r.out_datagrams, + &r.rcv_buf_errors, + &r.snd_buf_errors, + &r.in_csum_errors); + } + } + } + fclose(f); + } +#endif + r.ok = true; + + return true; +} + +SrsSnmpUdpStat* srs_get_udp_snmp_stat() +{ + return &_srs_snmp_udp_stat; +} + +void srs_update_udp_snmp_statistic() +{ + SrsSnmpUdpStat r; + if (!get_udp_snmp_statistic(r)) { + return; + } + + SrsSnmpUdpStat& o = _srs_snmp_udp_stat; + if (o.rcv_buf_errors > 0) { + r.rcv_buf_errors_delta = int(r.rcv_buf_errors - o.rcv_buf_errors); + } + + if (o.snd_buf_errors > 0) { + r.snd_buf_errors_delta = int(r.snd_buf_errors - o.snd_buf_errors); + } + + _srs_snmp_udp_stat = r; +} + SrsNetworkDevices::SrsNetworkDevices() { ok = false; diff --git a/trunk/src/app/srs_app_utility.hpp b/trunk/src/app/srs_app_utility.hpp index 63bfef577..117f7e67d 100644 --- a/trunk/src/app/srs_app_utility.hpp +++ b/trunk/src/app/srs_app_utility.hpp @@ -547,6 +547,48 @@ extern SrsPlatformInfo* srs_get_platform_info(); // The daemon st-thread will update it. extern void srs_update_platform_info(); +class SrsSnmpUdpStat +{ +public: + // Whether the data is ok. + bool ok; + // send and recv buffer error delta + int rcv_buf_errors_delta; + int snd_buf_errors_delta; + +public: + // @see: cat /proc/uptimecat /proc/net/snmp|grep 'Udp:' + // @see: https://blog.packagecloud.io/eng/2017/02/06/monitoring-tuning-linux-networking-stack-sending-data/#procnetsnmp + // InDatagrams: incremented when recvmsg was used by a userland program to read datagram. + // also incremented when a UDP packet is encapsulated and sent back for processing. + unsigned long long in_datagrams; + // NoPorts: incremented when UDP packets arrive destined for a port where no program is listening. + unsigned long long no_ports; + // InErrors: incremented in several cases: no memory in the receive queue, when a bad checksum is seen, + // and if sk_add_backlog fails to add the datagram. + unsigned long long in_errors; + // OutDatagrams: incremented when a UDP packet is handed down without error to the IP protocol layer to be sent. + unsigned long long out_datagrams; + // RcvbufErrors: incremented when sock_queue_rcv_skb reports that no memory is available; + // this happens if sk->sk_rmem_alloc is greater than or equal to sk->sk_rcvbuf. + unsigned long long rcv_buf_errors; + // SndbufErrors: incremented if the IP protocol layer reported an error when trying to send the packet + // and no error queue has been setup. also incremented if no send queue space or kernel memory are available. + unsigned long long snd_buf_errors; + // InCsumErrors: incremented when a UDP checksum failure is detected. + // Note that in all cases I could find, InCsumErrors is incremented at the same time as InErrors. + // Thus, InErrors - InCsumErros should yield the count of memory related errors on the receive side. + unsigned long long in_csum_errors; +public: + SrsSnmpUdpStat(); + ~SrsSnmpUdpStat(); +}; + +// Get SNMP udp statistic, use cache to avoid performance problem. +extern SrsSnmpUdpStat* srs_get_udp_snmp_stat(); +// The daemon st-thread will update it. +void srs_update_udp_snmp_statistic(); + // The network device summary for each network device, for example, eth0, eth1, ethN class SrsNetworkDevices {