Ori.livneh has submitted this change and it was merged.
Change subject: add varnishstatsd
......................................................................
add varnishstatsd
varnishstatsd is a Python script that reports varnish backend response times
and varnish backend response codes to statsd. The key names it generates look
like this:
varnish.backends.{backend}.{status}
varnish.backends.{backend}.{method}
For example:
varnish.backends.ipv4_10_2_2_27.2xx:1|c
varnish.backends.ipv4_10_2_2_27.GET:48|ms
Change-Id: I5fb6808be0a72167a17440702f356e517ebae34e
---
A modules/varnish/files/varnishstatsd
A modules/varnish/manifests/logging/statsd.pp
A modules/varnish/templates/initscripts/varnishstatsd.systemd.erb
3 files changed, 216 insertions(+), 0 deletions(-)
Approvals:
Ori.livneh: Looks good to me, approved
jenkins-bot: Verified
diff --git a/modules/varnish/files/varnishstatsd
b/modules/varnish/files/varnishstatsd
new file mode 100755
index 0000000..ca7e0ac
--- /dev/null
+++ b/modules/varnish/files/varnishstatsd
@@ -0,0 +1,148 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+ varnishstatsd
+ ~~~~~~~~~~~~~
+ Report backend response times and request counts aggregated by status.
+
+ Copyright 2015 Ori Livneh <[email protected]>
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+"""
+import argparse
+import collections
+import io
+import socket
+import urlparse
+from varnishlog import varnishlog
+
+
+METRIC_FORMAT = (
+ '%(key_prefix)s%(backend)s.%(method)s:%(ttfb)d|ms\n'
+ '%(key_prefix)s%(backend)s.%(status)s:1|c\n'
+)
+
+UDP_MTU_BYTES = 1472
+
+vsl_args = [
+ ('i', 'Backend'),
+ ('i', 'BackendXID'),
+ ('i', 'ReqEnd'),
+ ('i', 'RxStatus'),
+ ('i', 'TxRequest'),
+]
+
+sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+
+
+def parse_statsd_server_string(server_string):
+ parsed = urlparse.urlparse('//' + server_string)
+ return parsed.hostname, parsed.port or 8125
+
+
+def parse_key_prefix(key_prefix):
+ return key_prefix.strip('.') + '.'
+
+
+ap = argparse.ArgumentParser(
+ description='Varnish backend response time metric logger',
+ epilog='If no statsd server is specified, prints stats to stdout instead.'
+)
+ap.add_argument('--varnish-name', help='varnish name')
+ap.add_argument('--statsd-server', help='statsd server',
+ type=parse_statsd_server_string, default=None)
+ap.add_argument('--key-prefix', help='metric key prefix',
+ default='varnish.backends',
+ type=parse_key_prefix)
+args = ap.parse_args()
+
+if args.varnish_name:
+ vsl_args.append(('n', args.varnish_name))
+
+# Maximum number of log records to keep in memory.
+MAX_BACKLOG = 100
+
+# Map of transaction ID: request method ('GET', 'POST', etc.)
+tids = collections.OrderedDict()
+
+# Map of backend XID: transaction ID
+xids = collections.OrderedDict()
+
+# Map of transaction ID: backend name
+backends = collections.OrderedDict()
+
+# Map of transaction ID: response status code (200, 404, etc.)
+statuses = collections.OrderedDict()
+
+buf = io.BytesIO()
+
+
+def vsl_callback(transaction_id, tag, record, remote_party):
+ global buf
+
+ if tag == 'Backend':
+ # Associate the transaction ID with the backend name.
+ tid, _, backend = record.split()
+ backends[int(tid)] = backend
+ if len(backends) > MAX_BACKLOG:
+ backends.popitem(last=False)
+
+ elif tag == 'BackendXID':
+ # Associate the backend XID with its transaction ID.
+ xids[record] = transaction_id
+ if len(xids) > MAX_BACKLOG:
+ xids.popitem(last=False)
+
+ elif tag == 'TxRequest' and remote_party == 'backend':
+ # Associate the transaction ID with the request method.
+ tids[transaction_id] = record
+ if len(tids) > MAX_BACKLOG:
+ tids.popitem(last=False)
+
+ elif tag == 'RxStatus' and remote_party == 'backend':
+ # Associate the transaction ID with the response status code.
+ statuses[transaction_id] = record[0] + 'xx'
+ if len(statuses) > MAX_BACKLOG:
+ statuses.popitem(last=False)
+
+ elif tag == 'ReqEnd':
+ # Collate data and emit metric.
+ parts = record.split()
+ xid = parts[0]
+
+ try:
+ tid = xids.pop(xid)
+ fields = {
+ 'key_prefix': args.key_prefix,
+ 'method': tids.pop(tid),
+ 'backend': backends.pop(tid),
+ 'status': statuses.pop(tid),
+ 'ttfb': round(1000 * float(parts[4])),
+ }
+ except KeyError:
+ return 0
+
+ metric_string = (METRIC_FORMAT % fields).encode('utf-8')
+ if buf.tell() + len(metric_string) >= UDP_MTU_BYTES:
+ buf.seek(io.SEEK_SET)
+ if args.statsd_server:
+ sock.sendto(buf.read(), args.statsd_server)
+ else:
+ print(buf.read().decode('utf-8', errors='replace').rstrip())
+ buf = io.BytesIO()
+ buf.write(metric_string)
+
+ return 0
+
+varnishlog(vsl_args, vsl_callback)
diff --git a/modules/varnish/manifests/logging/statsd.pp
b/modules/varnish/manifests/logging/statsd.pp
new file mode 100644
index 0000000..19db9f8
--- /dev/null
+++ b/modules/varnish/manifests/logging/statsd.pp
@@ -0,0 +1,59 @@
+# == Define: varnish::logging::statsd
+#
+# Report backend response time averages and response status
+# counts to StatsD.
+#
+# === Parameters
+#
+# [*instance_name*]
+# Varnish instance name. If not specified, monitor
+# the default instance.
+#
+# [*statsd_server*]
+# StatsD server address, in "host:port" format.
+# Defaults to localhost:8125.
+#
+# [*metric_prefix*]
+# A prefix to prepend to all metric names.
+# Defaults to "varnish.backends".
+#
+# === Examples
+#
+# varnish::logging::statsd { 'frontend':
+# instance_name => 'frontend
+# statsd_server => 'statsd.eqiad.wmnet:8125
+# metric_prefix => 'varnish.backends',
+# }
+#
+define varnish::logging::statsd(
+ $instance_name = '',
+ $statsd_server = 'statsd',
+ $metric_prefix = 'varnish.backends',
+) {
+ if $instance_name {
+ $service_unit_name = "varnishstatsd-${instance_name}"
+ } else {
+ $service_unit_name = "varnishstatsd-default"
+ }
+
+ if ! defined(File['/usr/local/bin/varnishstatsd']) {
+ file { '/usr/local/bin/varnishstatsd':
+ source => 'puppet:///modules/varnish/varnishstatsd',
+ owner => 'root',
+ group => 'root',
+ mode => '0555',
+ require =>
File['/usr/local/lib/python2.7/dist-packages/varnishlog.py'],
+ }
+ }
+
+ base::service_unit { $service_unit_name:
+ ensure => present,
+ systemd => true,
+ strict => false,
+ template_name => 'varnishstatsd',
+ require => File['/usr/local/bin/varnishstatsd'],
+ service_params => {
+ enable => true,
+ },
+ }
+}
diff --git a/modules/varnish/templates/initscripts/varnishstatsd.systemd.erb
b/modules/varnish/templates/initscripts/varnishstatsd.systemd.erb
new file mode 100644
index 0000000..dc21f1c
--- /dev/null
+++ b/modules/varnish/templates/initscripts/varnishstatsd.systemd.erb
@@ -0,0 +1,9 @@
+[Unit]
+Description=Varnish StatsD reporter
+After=varnish<%= /\w/.match(@instance_name) ? "-#{@instance_name}" : ''
-%>.service
+
+[Service]
+ExecStart=/usr/local/bin/varnishstatsd <%= /\w/.match(@instance_name) ?
"--varnish-instance_name=#{@instance_name}" : "" %> --statsd-server=<%=
@statsd_server %>
+
+[Install]
+WantedBy=multi-user.target
--
To view, visit https://gerrit.wikimedia.org/r/214147
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I5fb6808be0a72167a17440702f356e517ebae34e
Gerrit-PatchSet: 8
Gerrit-Project: operations/puppet
Gerrit-Branch: production
Gerrit-Owner: Ori.livneh <[email protected]>
Gerrit-Reviewer: Alexandros Kosiaris <[email protected]>
Gerrit-Reviewer: BBlack <[email protected]>
Gerrit-Reviewer: Faidon Liambotis <[email protected]>
Gerrit-Reviewer: Filippo Giunchedi <[email protected]>
Gerrit-Reviewer: Giuseppe Lavagetto <[email protected]>
Gerrit-Reviewer: Ori.livneh <[email protected]>
Gerrit-Reviewer: Ottomata <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits