Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Logs & metrics: use the force, gain the insight - FIL2014

Logs & metrics: use the force, gain the insight - FIL2014

Centralized logging & metrics talk at Future Insights Live Las Vegas 2014

Thijs Feryn

June 18, 2014
Tweet

More Decks by Thijs Feryn

Other Decks in Technology

Transcript

  1. Logs & metrics Use the force, gain the insight By

    Thijs Feryn
  2. Hi, I’m Thijs

  3. I’m @ThijsFeryn on Twitter

  4. I’m an at Evangelist

  5. I’m a at board member

  6. None
  7. Insight & Knowledge

  8. Insight & knowledge ✓Google Analytics ✓Server logs ✓Application logs ✓Server

    resource usage ✓Server alerts
  9. Strategy

  10. Hold on to your butts

  11. Chapter 1 Centralizing logs

  12. Traditional log setup Server 1 Server 2 Server 3 •

    access_log • error_log • syslog • access_log • error_log • syslog • access_log • error_log • syslog
  13. Search? ✓Grep ✓Separate search on each machine ✓No graphing ✓Resource

    intensive on large files
  14. syslog-ng

  15. syslog-ng? ✓Still grep ✓All logs are centrally stored ✓Still separate

    files per server per date ✓Still no graphing ✓Still resource intensive on large files
  16. What do we need?

  17. What do we need? ✓Single storage point ✓Search all data

    at once ✓Fast & scalable search ✓Filter data ✓Convert logs into usable data ✓Visualize data
  18. Logstash can do that! http://logstash.net

  19. Input Output Filter Files Logstash daemon Files/database/ service

  20. collectd drupal_dblog elasticsearch eventlog exec file ganglia gelf gemfire generator

    graphite heroku imap invalid_input irc jmx log4j lumberjack pipe puppet_facter rabbitmq rackspace redis relp s3 snmptrap sqlite sqs stdin stomp syslog tcp twitter udp unix varnishlog websocket wmi xmpp zenoss zeromq Logstash input
  21. advisor alter anonymize checksum cidr cipher clone collate csv date

    dns drop elapsed elasticsearch environment extractnumbers fingerprint gelfify geoip grep grok grokdiscovery i18n json json_encode kv metaevent metrics multiline mutate noop prune punct railsparallelrequest range ruby sleep split sumnumbers syslog_pri throttle translate unique urldecode useragent uuid wms wmts xml zeromq Logstash filter
  22. boundary circonus cloudwatch csv datadog datadog_metrics elasticsearch elasticsearch_http elasticsearch_river email

    exec file ganglia gelf gemfire google_bigquery google_cloud_storage graphite graphtastic hipchat http irc jira juggernaut librato loggly lumberjack metriccatcher mongodb nagios nagios_nsca null opentsdb pagerduty pipe rabbitmq rackspace redis redmine riak riemann s3 sns solr_http sqs statsd stdout stomp syslog tcp udp websocket xmpp zabbix zeromq Logstash output
  23. Let’s try something simple

  24. 217.21.177.69  -­‐  -­‐  [03/Jun/2014:12:37:52  +0000]  "GET   /  HTTP/1.1"  200

     483  "-­‐"  "Mozilla/5.0  (Macintosh;   Intel  Mac  OS  X  10.9;  rv:29.0)  Gecko/20100101   Firefox/29.0" /var/log/apache2/ access.log
  25. input  {          file  {    

                 type  =>  "apache"                  path  =>  "/var/log/apache2/access.log"          }                     }   output  {                  stdout  {  codec  =>  rubydebug  }   } /etc/logstash/conf.d/logtash.conf
  26. {                  

       "tags"  =>  [],              "@version"  =>  1,          "@timestamp"  =>  "2014-­‐06-­‐03T13:13:10.036+00:00",                      "host"  =>  "meten",                      "file"  =>  "/var/log/apache2/access.log",                "message"  =>  "217.21.177.69  -­‐  -­‐  [03/Jun/ 2014:13:13:10  +0000]  \"GET  /  HTTP/1.1\"  200  483  \"-­‐\"   \"Mozilla/5.0  (Macintosh;  Intel  Mac  OS  X  10.9;  rv: 29.0)  Gecko/20100101  Firefox/29.0\"",                      "type"  =>  "apache"   } Nothing special, right?
  27. Let’s apply a filter

  28. input  {          file  {    

                 type  =>  "apache"                  path  =>  "/var/log/apache2/access.log"          }                     }   filter  {      grok  {            type  =>  "apache"          match  =>  ["message","%{COMBINEDAPACHELOG}"]      }   }   output  {                  stdout  {  codec  =>  rubydebug  }   }
  29. {                  

         "tags"  =>  [],                "@version"  =>  1,            "@timestamp"  =>  "2014-­‐06-­‐03T12:58:19.411+00:00",                        "host"  =>  "meten",                        "file"  =>  "/var/log/apache2/access.log",                  "message"  =>  "217.21.177.69  -­‐  -­‐  [03/Jun/2014:12:58:19  +0000]   \"GET  /  HTTP/1.1\"  200  482  \"-­‐\"  \"Mozilla/5.0  (Macintosh;  Intel  Mac   OS  X  10.9;  rv:29.0)  Gecko/20100101  Firefox/29.0\"",                        "type"  =>  "apache",                "clientip"  =>  "217.21.177.69",                      "ident"  =>  "-­‐",                        "auth"  =>  "-­‐",              "timestamp"  =>  "03/Jun/2014:12:58:19  +0000",                        "verb"  =>  "GET",                  "request"  =>  "/",          "httpversion"  =>  "1.1",                "response"  =>  "200",                      "bytes"  =>  "482",                "referrer"  =>  "\"-­‐\"",                      "agent"  =>  "\"Mozilla/5.0  (Macintosh;  Intel  Mac  OS  X  10.9;   rv:29.0)  Gecko/20100101  Firefox/29.0\""   } Looks more like it, huh?
  30. input  {          file  {    

                 type  =>  "apache"                  path  =>  "/var/log/apache2/access.log"          }                     }   filter  {      grok  {            type  =>  "apache"          match  =>  ["message","%{COMBINEDAPACHELOG}"]      }   }   output  {                  stdout  {  codec  =>  rubydebug  }   } What’s this GROK thing?
  31. Grok is currently the best way in logstash to parse

    crappy unstructured log data into something structured and queryable. This tool is perfect for syslog logs, apache and other webserver logs, mysql logs, and in general, any log format that is generally written for humans and not computer consumption. Logstash ships with about 120 patterns by default. You can find them here: https:// github.com/logstash/logstash/tree/v1.4.1/ patterns. You can add your own trivially. (See the patterns_dir setting) If you need help building patterns to match your logs, you will find the http:// grokdebug.herokuapp.com too quite useful!
  32. Grok patterns 123 Thijs Feryn %{number:myNumber}  %{firstname:myFirstname}  % {lastname:myLastname} number

     [0-­‐9+]   firstname  [A-­‐Z][a-­‐z]+   lastname  %{firstname} Input Pattern Custom patterns
  33. {      "myNumber":  [          [

                 "3"          ]      ],      "myFirstname":  [          [              "Thijs"          ]      ],      "myLastname":  [          [              "Feryn"          ]      ],      "firstname":  [          [              "Feryn"          ]      ]   } Grok patterns Result
  34. SYSLOGTIMESTAMP  %{MONTH}  +%{MONTHDAY}  %{TIME}   PROG  (?:[\w._/%-­‐]+)   SYSLOGPROG  %{PROG:program}(?:\[%{POSINT:pid}\])?

      SYSLOGHOST  %{IPORHOST}   SYSLOGFACILITY  <%{NONNEGINT:facility}.%{NONNEGINT:priority} >   HTTPDATE  %{MONTHDAY}/%{MONTH}/%{YEAR}:%{TIME}  %{INT}   ! ! QS  %{QUOTEDSTRING}   ! SYSLOGBASE  %{SYSLOGTIMESTAMP:timestamp}  (?:% {SYSLOGFACILITY}  )?%{SYSLOGHOST:logsource}  %{SYSLOGPROG}:   COMMONAPACHELOG  %{IPORHOST:clientip}  %{USER:ident}  % {USER:auth}  \[%{HTTPDATE:timestamp}\]  "(?:%{WORD:verb}  % {NOTSPACE:request}(?:  HTTP/%{NUMBER:httpversion})?|% {DATA:rawrequest})"  %{NUMBER:response}  (?:% {NUMBER:bytes}|-­‐)   COMBINEDAPACHELOG  %{COMMONAPACHELOG}  %{QS:referrer}  % {QS:agent}
  35. Let’s add another cool filter

  36. input  {          file  {    

                 type  =>  "apache"                  path  =>  "/var/log/apache2/access.log"          }                     }   filter  {      grok  {            type  =>  "apache"          match  =>  ["message","%{COMBINEDAPACHELOG}"]      }      geoip  {          source  =>  "clientip"          target  =>  "geoip"      }   }   output  {                  stdout  {  codec  =>  rubydebug  }   }
  37. {                  

         "tags"  =>  [],                "@version"  =>  1,            "@timestamp"  =>  "2014-­‐06-­‐03T13:57:04.498+00:00",                        "host"  =>  "meten",                        "file"  =>  "/var/log/apache2/access.log",                  "message"  =>  "217.21.177.69  -­‐  -­‐  [03/Jun/2014:13:33:22  +0000]  \"GET  /  HTTP/1.1\"  200   482  \"-­‐\"  \"Mozilla/5.0  (Macintosh;  Intel  Mac  OS  X  10.9;  rv:29.0)  Gecko/20100101  Firefox/ 29.0\"",                        "type"  =>  "apache",                "clientip"  =>  "217.21.177.69",                      "ident"  =>  "-­‐",                        "auth"  =>  "-­‐",              "timestamp"  =>  "03/Jun/2014:13:33:22  +0000",                        "verb"  =>  "GET",                  "request"  =>  "/",          "httpversion"  =>  "1.1",                "response"  =>  "200",                      "bytes"  =>  "482",                "referrer"  =>  "\"-­‐\"",                      "agent"  =>  "\"Mozilla/5.0  (Macintosh;  Intel  Mac  OS  X  10.9;  rv:29.0)  Gecko/20100101   Firefox/29.0\"",                      "geoip"  =>  {                                              "ip"  =>  "217.21.177.69",                        "country_code2"  =>  "BE",                        "country_code3"  =>  "BEL",                          "country_name"  =>  "Belgium",                      "continent_code"  =>  "EU",                            "region_name"  =>  "08",                                "city_name"  =>  "Gent",                                  "latitude"  =>  51.05000000000001,                                "longitude"  =>  3.75,                                  "timezone"  =>  "Europe/Brussels",                  "real_region_name"  =>  "Oost-­‐Vlaanderen",                                  "location"  =>  [                          [0]  3.75,                          [1]  51.05000000000001                  ]          } GeoIP magic
  38.                  "geoip"  =>

     {                                            "ip"  =>  "217.21.177.69",                      "country_code2"  =>  "BE",                      "country_code3"  =>  "BEL",                        "country_name"  =>  "Belgium",                    "continent_code"  =>  "EU",                          "region_name"  =>  "08",                              "city_name"  =>  "Gent",                                "latitude"  =>  51.05000000000001,                              "longitude"  =>  3.75,                                "timezone"  =>  "Europe/Brussels",                "real_region_name"  =>  "Oost-­‐Vlaanderen",                                "location"  =>  [                        [0]  3.75,                        [1]  51.05000000000001                ]        }
  39. Let’s send these logs some place useful

  40. Give it up for http://elasticsearch.org

  41. Elasticsearch is a flexible and powerful open source, distributed, real-time

    search and analytics engine. Architected from the ground up for use in distributed environments where reliability and scalability are must haves, Elasticsearch gives you the ability to move easily beyond simple full-text search. Through its robust set of APIs and query DSLs, plus clients for the most popular programming languages, Elasticsearch delivers on the near limitless promises of search technology
  42. input  {          file  {    

                 type  =>  "apache"                  path  =>  "/var/log/apache2/access.log"          }                     }   filter  {      grok  {            type  =>  "apache"          match  =>  ["message","%{COMBINEDAPACHELOG}"]      }      geoip  {          source  =>  "clientip"          target  =>  "geoip"      }   }   output  {                  stdout  {  codec  =>  rubydebug  }          elasticsearch  {  host  =>  "localhost"  }   }
  43. Logstash + ElasticSearch • access_log • error_log • syslog •

    access_log • error_log • syslog • access_log • error_log • syslog ElasticSearch Server 2 + Logstash Server 1 + Logstash Server 3 + Logstash
  44. Logstash ElasticSearch glossary ✓Database is called an „index” ✓Table is

    called a „type” ✓Row is called a „document” ✓Schema-less (sort of), but Logstash applies its own custom schema ✓Logstash creates a daily index ✓Input types are stored in ElasticSearch types ✓Each log is a document of a certain type in the index of that day.
  45. Querying ElasticSearch curl  http://localhost:9200/_search?pretty

  46. {      "took"  :  36,      "timed_out"  :

     false,      "_shards"  :  {          "total"  :  5,          "successful"  :  5,          "failed"  :  0      },      "hits"  :  {          "total"  :  1,          "max_score"  :  1.0,          "hits"  :  [  {              "_index"  :  "logstash-­‐2014.06.03",              "_type"  :  "apache",              "_id"  :  "OS81NlYWTQu4j4O5OZMmXA",              "_score"  :  1.0,              "_source":{"tags":[],"@version": 1,"@timestamp":"2014-­‐06-­‐03T14:37:07.119Z","host":"meten","file":"/var/log/apache2/ access.log","message":"10.10.10.1  -­‐  -­‐  [03/Jun/2014:14:37:07  +0000]  \"GET  /  HTTP/1.1\"  200   483  \"-­‐\"  \"Mozilla/5.0  (Macintosh;  Intel  Mac  OS  X  10.9;  rv:29.0)  Gecko/20100101  Firefox/ 29.0\"","type":"apache","clientip":"217.21.177.69","ident":"-­‐","auth":"-­‐","timestamp":"03/ Jun/2014:14:37:07   +0000","verb":"GET","request":"/","httpversion":"1.1","response":"200","bytes":"483","referr er":"\"-­‐\"","agent":"\"Mozilla/5.0  (Macintosh;  Intel  Mac  OS  X  10.9;  rv:29.0)  Gecko/20100101   Firefox/29.0\"","geoip": {"ip":"217.21.177.69","country_code2":"BE","country_code3":"BEL","country_name":"Belgium","c ontinent_code":"EU","region_name":"08","city_name":"Gentbrugge","latitude": 51.05000000000001,"longitude":3.75,"timezone":"Europe/Brussels","real_region_name":"Oost-­‐ Vlaanderen","location":[3.75,51.05000000000001]}}          }  ]      }   }  
  47.  "hits"  :  {          "total"  :  1,

             "max_score"  :  1.0,          "hits"  :  [  {              "_index"  :  "logstash-­‐2014.06.03",              "_type"  :  "apache",              "_id"  :  "OS81NlYWTQu4j4O5OZMmXA",              "_score"  :  1.0,              "_source":{"tags":[],"@version": 1,"@timestamp":"2014-­‐06-­‐03T14:37:07.119Z","host":"meten","file": access.log","message":"10.10.10.1  -­‐  -­‐  [03/Jun/2014:14:37:07  +000 \"-­‐\"  \"Mozilla/5.0  (Macintosh;  Intel  Mac  OS  X  10.9;  rv:29.0)  Ge 29.0\"","type":"apache","clientip":"217.21.177.69","ident":"-­‐"," 2014:14:37:07   +0000","verb":"GET","request":"/","httpversion":"1.1","response" "\"-­‐\"","agent":"\"Mozilla/5.0  (Macintosh;  Intel  Mac  OS  X  10.9;   29.0\"","geoip": {"ip":"217.21.177.69","country_code2":"BE","country_code3":"BEL" nent_code":"EU","region_name":"08","city_name":"Gentbrugge","lat 51.05000000000001,"longitude":3.75,"timezone":"Europe/Brussels", Vlaanderen","location":[3.75,51.05000000000001]}}          }  ]  
  48. {      "template"  :  "logstash-­‐*",      "settings"  :

     {          "index.refresh_interval"  :  "5s"      },      "mappings"  :  {          "_default_"  :  {                "_all"  :  {"enabled"  :  true},                "dynamic_templates"  :  [  {                    "string_fields"  :  {                        "match"  :  "*",                        "match_mapping_type"  :  "string",                        "mapping"  :  {                            "type"  :  "string",  "index"  :  "analyzed",  "omit_norms"  :   true,                                "fields"  :  {                                    "raw"  :  {"type":  "string",  "index"  :  "not_analyzed",   "ignore_above"  :  256}                                }                        }                    }                }  ],                "properties"  :  {                    "@version":  {  "type":  "string",  "index":  "not_analyzed"  },                    "geoip"    :  {                        "type"  :  "object",                            "dynamic":  true,                            "path":  "full",                            "properties"  :  {                                "location"  :  {  "type"  :  "geo_point"  }                            }                    }                }          }      }   } Logstash mapping
  49. How is that useful?

  50. Logstash ElasticSearch ✓Centralized storage ✓„Infinitely” scalable ( -> clustering) ✓Fast

    & detailed search ✓Automatic schema mapping ✓Simple to configure ✓Simple to query ✓Ménage à 3
  51. http://www.elasticsearch.org/overview/kibana/

  52. Kibana ✓Reads Logstash data out of ElasticSearch ✓Written entirely in

    HTML, Javascript & CSS (no server-side code) ✓Visualizes logs ✓Customizable panels ✓Supported by the ElasticSearch & Logstash team ✓Almost zero config
  53. Logstash ! ElasticSearch ! Kibana

  54. Logstash ! ElasticSearch ! Kibana The ELK stack

  55. Out of the box

  56. None
  57. Search Visualize Overview Filter

  58. Let’s use the location data

  59. None
  60. None
  61. None
  62. None
  63. Do it yourself

  64. curl  http://weten.dev:9200/_search?pretty  -­‐d'   {          "from":

     0,          "size":  100,          "query"  :          {                  "filtered"  :                  {                          "query"  :                          {                                  "match_all"  :  {}                          },                          "filter"  :  {                                  "and"  :  [                                          {                                                  "range":                                                  {                                                          "@timestamp"  :  {                                                                  "from":  "2014-­‐06-­‐02T10:00:00Z",                                                                  "to":  "2014-­‐06-­‐04T16:00:00Z"                                                          }                                                  }                                          },                                          {                                                  "term":                                                  {                                                          "geoip.country_code2.raw":  "DE"                                                  }                                          }                                  ]                          }                  }          },          "sort"  :  [                  {"@timestamp"  :  {"order"  :  "desc"}}          ]   }'
  65. curl  http://weten.dev:9200/logstash-­‐2014.06.04/apache/_search?pretty  -­‐ d'   {        

     "from":  0,          "size":  100,          "query"  :          {                  "filtered"  :                  {                          "query"  :                          {                                  "match_all"  :  {}                          },                          "filter"  :  {                                  "term":                                  {                                          "geoip.country_code2.raw":  "DE"                                  }                          }                  }          },          "sort"  :  [                  {"@timestamp"  :  {"order"  :  "desc"}}          ]   }' ~database ~table
  66. http://weten.dev:9200/_search?pretty   http://weten.dev:9200/logstash-­‐2014.06.03/_search? pretty   http://weten.dev:9200/logstash-­‐2014.06.*/apache/ _search?pretty   http://weten.dev:9200/ logstash-­‐2014.06.03,logstash-­‐2014.06.04/apache/

    _search?pretty Index/type variations
  67. Aggregations group by on steroids http://www.elasticsearch.org/guide/en/elasticsearch/ reference/current/search-aggregations.html

  68. curl  "http://weten.dev:9200/_search?pretty"  -­‐d'   {        "size":  0,

           "aggregations":  {              "countries":  {                    "terms":  {                          "field":  "geoip.country_name.raw"                    }              }        }   }' Value counting
  69.        "total"  :  16,        

     "max_score"  :  0.0,          "hits"  :  [  ]      },      "aggregations"  :  {          "countries"  :  {              "buckets"  :  [  {                  "key"  :  "Belgium",                  "doc_count"  :  8              },  {                  "key"  :  "Germany",                  "doc_count"  :  7              },  {                  "key"  :  "United  Kingdom",                  "doc_count"  :  1              }  ]          }      }   }
  70. curl  http://weten.dev:9200/_search?pretty  -­‐d'   {          "aggs"

     :  {                  "how_far_from_amsterdam"  :  {                          "geo_distance"  :  {                                  "field"  :  "geoip.location",                                  "origin"  :  "52.3760,  4.894",                                  "unit"  :  "km",                                  "ranges"  :  [                                          {  "to"  :  100  },                                          {  "from"  :  100,  "to"  :  300  },                                          {  "from"  :  300  }                                  ]                          }                  }          }   }' Geo distance
  71.        "hits"  :  [  ]      },

         "aggregations"  :  {          "how_far_from_amsterdam"  :  {              "buckets"  :  [  {                  "key"  :  "*-­‐100.0",                  "from"  :  0.0,                  "to"  :  100.0,                  "doc_count"  :  0              },  {                  "key"  :  "100.0-­‐300.0",                  "from"  :  100.0,                  "to"  :  300.0,                  "doc_count"  :  8              },  {                  "key"  :  "300.0-­‐*",                  "from"  :  300.0,                  "doc_count"  :  8              }  ]          }      }   }
  72. Should Logstash run on all my machines?

  73. Nope! That would be kinda heavy on your system

  74. Ship logs to a central Logstash system

  75. Centralized Logstash Server 1 Server 2 Server 3 Redis Logstash

    ElasticSearch Shipper required
  76. Logstash shippers ✓Beaver (python) ✓Woodchuck (ruby) ✓Awesant (perl) ✓Lumberjack (c)

    ✓Syslog-shipper (ruby) ✓Remote_syslog (ruby) ✓Message::Passing (perl) ✓Nxlog (c) ✓Logtail (perl) ✓Node-logstash (javascript)
  77. I like Beaver https://github.com/josegonzalez/beaver http://redis.io It can use Redis as

    a message queue
  78. [beaver]   transport:  redis   redis_url:  redis://10.10.10.37:6379/0   redis_namespace:  apache

      logstash_version:  1   [/var/log/apache2/access.log]   type:  apache Beaver conf file
  79. input  {          redis  {    

                 host  =>  "localhost"          type  =>  "apache"                  key  =>  "apache"                  data_type  =>  "list"          }                     }   filter  {          grok  {                    type  =>  "apache"                  match  =>  ["message","%{COMBINEDAPACHELOG}"]          }              geoip  {                  source  =>  "clientip"                  target  =>  "geoip"          }   }   output  {                  stdout  {  codec  =>  rubydebug  }          elasticsearch  {  host  =>  "localhost"  }   }   Logstash conf file
  80. Chapter 2 Server metrics

  81. Other measurement points Not coming from logs

  82. Collectd Collect server metrics https://collectd.org

  83. LoadPlugin  apache   LoadPlugin  cpu   LoadPlugin  df   LoadPlugin

     disk   LoadPlugin  interface   LoadPlugin  load   LoadPlugin  memory   LoadPlugin  processes   LoadPlugin  swap   LoadPlugin  write_graphite   <Plugin  apache>     <Instance  "meten">       URL  "http://localhost/server-­‐status?auto"     </Instance>   </Plugin>   <Plugin  write_graphite>     <Carbon>       Host  "10.10.10.37"       Port  "2003"       StoreRates  false       AlwaysAppendDS  false       EscapeCharacter  "_"     </Carbon>   </Plugin> /etc/collectd/ collectd.conf What’s Graphite?
  84. Graphite Store numeric, time-series data & render real-time graphs on

    demand http://graphite.wikidot.com
  85. None
  86. Graphite is not just a dashboard, it comes with an

    API
  87. http://weten.dev/render? from=-­‐1minutes&until=now&width=400&height=2 50&target=meten_dev.load.load.shortterm&are aMode=stacked&connectedLimit=&_uniq=0.31136 49664673026&title=meten_dev.load.load.short term

  88. http://weten.dev/render? from=-­‐1minutes&until=now&width=400&height=2 50&target=meten_dev.load.load.shortterm&are aMode=stacked&connectedLimit=&_uniq=0.31136 49664673026&title=meten_dev.load.load.short term&format=json

  89. [{"target":  "meten_dev.load.load.shortterm",   "datapoints":  [[null,  1401810412],  [null,   1401810413],  [null,

     1401810414],  [1.27,  1401810415],   [null,  1401810416],  [null,  1401810417],  [null,   1401810418],  [null,  1401810419],  [null,  1401810420],   [null,  1401810421],  [null,  1401810422],  [null,   1401810423],  [null,  1401810424],  [1.07,  1401810425],   [null,  1401810426],  [null,  1401810427],  [null,   1401810428],  [null,  1401810429],  [null,  1401810430],   [null,  1401810431],  [null,  1401810432],  [null,   1401810433],  [null,  1401810434],  [1.05,  1401810435],   [null,  1401810436],  [null,  1401810437],  [null,   1401810438],  [null,  1401810439],  [null,  1401810440],   [null,  1401810441],  [null,  1401810442],  [null,   1401810443],  [null,  1401810444],  [1.59,  1401810445],   [null,  1401810446],  [null,  1401810447],  [null,   1401810448],  [null,  1401810449],  [null,  1401810450],   [null,  1401810451],  [null,  1401810452],  [null,  
  90. Graphite output formats ✓Raw ✓Json ✓Png ✓Csv ✓Svg

  91. The Graphite dashboard looks kinda ugly, right?

  92. None
  93. There are alternatives that leverage the API

  94. Alternative Graphite dashboards ✓Giraffe ✓Graphene ✓GDash ✓… http://graphite.readthedocs.org/en/latest/tools.html

  95. Let’s have a look at Graphene

  96. http://jondot.github.io/graphene/

  97. <html>      <head>          <title>Dashboard</title>  

           <link  rel="stylesheet"  href="/build/ index.css"  type="text/css"  media="screen"   charset="utf-­‐8">      </head>      <body>                  <div  id="graph"></div>          <script  type="text/javascript"  src="/vendor/ js/jquery-­‐1.7.1.min.js"></script>          <script  type="text/javascript"  src="/build/ index.js"></script>                  <script  type="text/javascript"  src="example-­‐ dash.js"></script>                          </body>   </html>
  98. description  =  {      "Load"  :    {  

       source:     "http://weten.dev/render? from=-­‐2minutes&until=now&target=meten_dev.load.load.s hortterm&format=json",      TimeSeries:  {              parent:  "#graph",              title:  "Load",              ymax:  "40",                        width:  "800",              height:  "300",      },    }   }   var  g  =  new  Graphene;   g.build(description);
  99. It turns this …

  100. None
  101. Into this …

  102. Chapter 3 Application metrics

  103. Sending real-time stats from your within your code

  104. Statsd https://github.com/etsy/statsd/

  105. Statsd ✓Written in Nodejs ✓Listens for stats, counters & timers

    ✓Communicates over UDP ✓Pluggable backends (e.g. Graphite) ✓Client libraries for all popular languages
  106. Statsd node  stats.js  config.js {      graphitePort:  2003  

    ,  graphiteHost:  "graphite.example.com"   ,  port:  8125   ,  backends:  [  "./backends/graphite"  ]   } example config
  107. PHP & Statsd https://github.com/domnikl/statsd-php <?php! $connection = new \Domnikl\Statsd\Connection \Socket('localhost',

    8125);! $statsd = new \Domnikl\Statsd \Client($connection, "test.namespace");! ! // simple counts! $statsd->increment("foo.bar");! $statsd->decrement("foo.bar");! $statsd->count("foo.bar", 1000);
  108. <?php! $connection = new \Domnikl\Statsd\Connection\Socket('localhost', 8125);! $statsd = new \Domnikl\Statsd\Client($connection,

    "test.namespace");! ! // the global namespace is prepended to every key (optional)! $statsd->setNamespace("test");! ! // simple counts! $statsd->increment("foo.bar");! $statsd->decrement("foo.bar");! $statsd->count("foo.bar", 1000);! ! // timing! $statsd->timing("foo.bar", 320);! $statsd->time("foo.bar.bla", function() {! // code to be measured goes here ...! });! ! // more complex timings can be handled with startTiming() and endTiming( )! $statsd->startTiming("foo.bar");! // more complex code here ...! $statsd->endTiming("foo.bar");! ! // memory profiling! $statsd->startMemoryProfile('memory.foo');! // some complex code goes here ...! $statsd->endMemoryProfile('memory.foo');! ! // report peak usage! $statsd->memory('foo.memory_peak_usage');! ! // gauges! $statsd->gauge('foobar', 3); PHP & Statsd
  109. Statsd client libraries ✓pystatsd (https://github.com/sivy/pystatsd) ✓statsd-ruby (https://github.com/github/statsd- ruby) ✓node-statsd (https://github.com/sivy/node-statsd)

    ✓statsd-csharp-client (https://github.com/ goncalopereira/statsd-csharp-client) ✓…
  110. Chapter 4 Log metrics

  111. Full circle

  112. Log metrics Server 1 Server 2 Server 3 Redis Logstash

    ElasticSearch Statsd Graphite
  113. output  {            statsd  {  

       type  =>  "apache"      host  =>  "localhost"      port  =>  8125      namespace  =>  "logstash"      increment  =>  "apache.country.%{[geopip] [country_code2]}"      increment  =>  "apache.response.%{response}"                      count  =>  [  "apache.bytes",  "%{bytes}"  ]    }   } Logstash statsd output
  114. Logstash stats

  115. Recap!

  116. ✓Centralize your logs ✓Visualize server metrics ✓Visualize application metrics ✓Visualize

    log metrics Action
  117. Beaver Redis Logstash ElasticSearch CollectD StatsD Graphite Graphene

  118. None