package nsqd

import (
    "fmt"
    "math"
    "runtime"
    "sort"
    "time"

    "github.com/nsqio/nsq/internal/statsd"
)

type Uint64Slice []uint64

func (s Uint64Slice) Len() int {
    return len(s)
}

func (s Uint64Slice) Swap(i, j int) {
    s[i], s[j] = s[j], s[i]
}

func (s Uint64Slice) Less(i, j int) bool {
    return s[i] < s[j]
}

func (n *NSQD) statsdLoop() {
    var lastMemStats runtime.MemStats
    var lastStats []TopicStats
    ticker := time.NewTicker(n.getOpts().StatsdInterval)
    for {
        select {
        case <-n.exitChan:
            goto exit
        case <-ticker.C:
            client := statsd.NewClient(n.getOpts().StatsdAddress, n.getOpts().StatsdPrefix)
            err := client.CreateSocket()
            if err != nil {
                n.logf("ERROR: failed to create UDP socket to statsd(%s)", client)
                continue
            }

            n.logf("STATSD: pushing stats to %s", client)

            stats := n.GetStats()
            for _, topic := range stats {
                // try to find the topic in the last collection
                lastTopic := TopicStats{}
                for _, checkTopic := range lastStats {
                    if topic.TopicName == checkTopic.TopicName {
                        lastTopic = checkTopic
                        break
                    }
                }
                diff := topic.MessageCount - lastTopic.MessageCount
                stat := fmt.Sprintf("topic.%s.message_count", topic.TopicName)
                client.Incr(stat, int64(diff))

                stat = fmt.Sprintf("topic.%s.depth", topic.TopicName)
                client.Gauge(stat, topic.Depth)

                stat = fmt.Sprintf("topic.%s.backend_depth", topic.TopicName)
                client.Gauge(stat, topic.BackendDepth)

                for _, item := range topic.E2eProcessingLatency.Percentiles {
                    stat = fmt.Sprintf("topic.%s.e2e_processing_latency_%.0f", topic.TopicName, item["quantile"]*100.0)
                    // We can cast the value to int64 since a value of 1 is the
                    // minimum resolution we will have, so there is no loss of
                    // accuracy
                    client.Gauge(stat, int64(item["value"]))
                }

                for _, channel := range topic.Channels {
                    // try to find the channel in the last collection
                    lastChannel := ChannelStats{}
                    for _, checkChannel := range lastTopic.Channels {
                        if channel.ChannelName == checkChannel.ChannelName {
                            lastChannel = checkChannel
                            break
                        }
                    }
                    diff := channel.MessageCount - lastChannel.MessageCount
                    stat := fmt.Sprintf("topic.%s.channel.%s.message_count", topic.TopicName, channel.ChannelName)
                    client.Incr(stat, int64(diff))

                    stat = fmt.Sprintf("topic.%s.channel.%s.depth", topic.TopicName, channel.ChannelName)
                    client.Gauge(stat, channel.Depth)

                    stat = fmt.Sprintf("topic.%s.channel.%s.backend_depth", topic.TopicName, channel.ChannelName)
                    client.Gauge(stat, channel.BackendDepth)

                    stat = fmt.Sprintf("topic.%s.channel.%s.in_flight_count", topic.TopicName, channel.ChannelName)
                    client.Gauge(stat, int64(channel.InFlightCount))

                    stat = fmt.Sprintf("topic.%s.channel.%s.deferred_count", topic.TopicName, channel.ChannelName)
                    client.Gauge(stat, int64(channel.DeferredCount))

                    diff = channel.RequeueCount - lastChannel.RequeueCount
                    stat = fmt.Sprintf("topic.%s.channel.%s.requeue_count", topic.TopicName, channel.ChannelName)
                    client.Incr(stat, int64(diff))

                    diff = channel.TimeoutCount - lastChannel.TimeoutCount
                    stat = fmt.Sprintf("topic.%s.channel.%s.timeout_count", topic.TopicName, channel.ChannelName)
                    client.Incr(stat, int64(diff))

                    stat = fmt.Sprintf("topic.%s.channel.%s.clients", topic.TopicName, channel.ChannelName)
                    client.Gauge(stat, int64(len(channel.Clients)))

                    for _, item := range channel.E2eProcessingLatency.Percentiles {
                        stat = fmt.Sprintf("topic.%s.channel.%s.e2e_processing_latency_%.0f", topic.TopicName, channel.ChannelName, item["quantile"]*100.0)
                        client.Gauge(stat, int64(item["value"]))
                    }
                }
            }
            lastStats = stats

            if n.getOpts().StatsdMemStats {
                var memStats runtime.MemStats
                runtime.ReadMemStats(&memStats)

                // sort the GC pause array
                length := len(memStats.PauseNs)
                if int(memStats.NumGC) < length {
                    length = int(memStats.NumGC)
                }
                gcPauses := make(Uint64Slice, length)
                copy(gcPauses, memStats.PauseNs[:length])
                sort.Sort(gcPauses)

                client.Gauge("mem.heap_objects", int64(memStats.HeapObjects))
                client.Gauge("mem.heap_idle_bytes", int64(memStats.HeapIdle))
                client.Gauge("mem.heap_in_use_bytes", int64(memStats.HeapInuse))
                client.Gauge("mem.heap_released_bytes", int64(memStats.HeapReleased))
                client.Gauge("mem.gc_pause_usec_100", int64(percentile(100.0, gcPauses, len(gcPauses))/1000))
                client.Gauge("mem.gc_pause_usec_99", int64(percentile(99.0, gcPauses, len(gcPauses))/1000))
                client.Gauge("mem.gc_pause_usec_95", int64(percentile(95.0, gcPauses, len(gcPauses))/1000))
                client.Gauge("mem.next_gc_bytes", int64(memStats.NextGC))
                client.Incr("mem.gc_runs", int64(memStats.NumGC-lastMemStats.NumGC))

                lastMemStats = memStats
            }

            client.Close()
        }
    }

exit:
    ticker.Stop()
}

func percentile(perc float64, arr []uint64, length int) uint64 {
    if length == 0 {
        return 0
    }
    indexOfPerc := int(math.Floor(((perc / 100.0) * float64(length)) + 0.5))
    if indexOfPerc >= length {
        indexOfPerc = length - 1
    }
    return arr[indexOfPerc]
}

statsd.go的更多相关文章

  1. #研发解决方案介绍#基于StatsD+Graphite的智能监控解决方案

    郑昀 基于李丹和刘奎的文档 创建于2014/12/5 关键词:监控.dashboard.PHP.graphite.statsd.whisper.carbon.grafana.influxdb.Pyth ...

  2. statsd+graphite

    一些观点: Statsd:一个nodejs的客户端,用于向graphite的收集器发送数据,使用各类编程语言的客户端响起发送timer,counter等统计数据后,其通过udp定时向graphite发 ...

  3. 使用statsd+graphite+grafana构建业务及性能监控模块

    近些年随着DevOps概念越来越收到重视,除了传统的Splunk,Zabbix外在开源领域也有越来越多的软件可供使用.从数据收集,时序数据库,图形展示等主要方面有各类可扩展的软件用于搭建一个数据监控平 ...

  4. 第三十三章 metrics(1) - graphite搭建 + whisper存储模式 + 高精度向低精度聚合方式 + 集成StatsD + 集成grafana

    组件介绍: carbon:Carbon实际上是一系列守护进程,组成一个Graphite安装的存储后端.这些守护进程用一个名为Twisted的事件驱动网络引擎监听时间序列数据.Twisted框架让Car ...

  5. 如何深入理解 StatsD 与 Graphite ?

    众所周知,StatsD 负责收集并聚合测量值.之后,它会将数据传给 Graphite,后者以时间序列为依据存储数据,并绘制图表.但是,我们不知道,基于 http 访问的图表在展示时,是基于每秒钟的请求 ...

  6. StatsD!次世代系统监控的核心

    在互联网业务蒸蒸日上的今时今日,系统架构日渐复杂,随着软件产品和工程团队的变革,许多开源的监控工具应运而生,其中有一些相当出名,比如 Zabbix.Nagios 还有 StatsD.也有一些问题被大家 ...

  7. 聊聊 Statsd 和 Collectd 那点事!

    StatsD 是由 Etsy 开发并发布的汇总和总结应用指标的一个简单的守护进程,近些年来发展迅速,已经变成了一个用于收集应用性能指标的统一的协议. 关于 Statsd 的使用已经有很多文章介绍过,所 ...

  8. Cloud Insight!StatsD 系监控产品新宠!

    年关将至,Cloud Insight 正式版悄然上线了.没有大张旗鼓的宣传,也没有热热闹闹的庆祝,只是一群人在上线前踏踏实实的优化了两周,然后发版,就是这样一件简单的事. 然而就是这样一个低调的产品, ...

  9. Swift开放StatsD后上传数据的出现,出现退换货503的Bug

    转载请注明出处:http://blog.csdn.net/cywosp/article/details/40781569 swift在版本号2.1.0之前假设各个服务的配置文件里打开下面配置后,且系统 ...

随机推荐

  1. [C#]使用 C# 编写自己的区块链挖矿算法

    [C#] 使用 C# 编写自己区块链的挖矿算法 文章原文来自:Code your own blockchain mining algorithm in Go! ,原始文章通过 Go 语言来实现的,这里 ...

  2. Resin4下JSP文件导出问题的解决

           之前我在Resin3下采用JSP代码对一些硬盘上的文件作读取以后再输出或者生成一些特殊格式文件(如Excel)再输出供下载,这些文件输出JSP代码在Resin4以后输出的文件都产生错误无 ...

  3. JeeSite数据分页与翻页

    本文章介绍的是JeeSite开源项目二次开发时的一些笔记,对于没有使用过JeeSite的可以不用往下看了,因为下面的代码是跟JeeSite二次开发相关的代码,不做JeeSite的二次开发,以下代码对您 ...

  4. 物流的纯css实现方法

    首先我们来看看UI给出的设计图. 为什么到达是最前面,为什么物流顺序是倒叙的,这是什么用户习惯,这是我拿到设计稿的问题,但是这里不谈设计,因为审美这个东西无法评估.那么这里我就做一个顺序的来对比一下吧 ...

  5. ArcCore重构-Makefile模块化

    基于官方arc-stable-9c57d86f66be,AUTOSAR版本3.1.5   基本问题 2. 编译系统中代码文件是否编译及目标文件集中定义在boards/board_common.mk,而 ...

  6. 网络-udp

    1. 网络:把双方或者多方的设备(电脑,智能手机,ipad等)连接起来的一个工具     1.1 学习网络的目的: 通过网络把数据从一方传递到另外一方,完成数据的共享 2. ip地址     2.1: ...

  7. 《T-SQL查询》读书笔记Part 1.逻辑查询处理知多少

    一.关于T-SQL T-SQL是ANSI和ISO SQL标准的MS SQL扩展,其正式名称为Transact-SQL,但一般程序员都称其为T-SQL. 二.逻辑查询处理各个阶段 2.1 逻辑查询处理流 ...

  8. 设计模式的征途—13.代理(Proxy)模式

    所谓代购,简单说来就是找人帮忙购买所需要的商品.代购分为两种类型,一种是因为在当地买不到某件商品,又或者是因为当地这件商品的价格比其他地区的贵,因此托人在其他地区甚至国外购买该商品,然后通过快递发货或 ...

  9. MicroService 微服务架构模式简述

    开源地址: https://github.com/TheCodeCleaner/MicroService4Net 本文内容 微服务 微服务风格的特性 组件化(Componentization )与服务 ...

  10. 几张图帮你理解 docker 基本原理及快速入门

    写的非常好的一篇文章,不知道为什么被删除了.  利用Google快照,做个存档. 快照地址:地址 作者地址:青牛 什么是docker Docker 是一个开源项目,诞生于 2013 年初,最初是 do ...