Yuvipanda has submitted this change and it was merged. Change subject: tools: Track per tool request stats in graphite ......................................................................
tools: Track per tool request stats in graphite Bug: T69880 Change-Id: Ie7f35a8946a4ff7cce93396964d2c2042d8017b6 --- M modules/dynamicproxy/manifests/init.pp A modules/toollabs/files/toolsweblogster.py M modules/toollabs/manifests/proxy.pp 3 files changed, 102 insertions(+), 16 deletions(-) Approvals: Yuvipanda: Looks good to me, approved jenkins-bot: Verified diff --git a/modules/dynamicproxy/manifests/init.pp b/modules/dynamicproxy/manifests/init.pp index 318b1b3..7f5b41e 100644 --- a/modules/dynamicproxy/manifests/init.pp +++ b/modules/dynamicproxy/manifests/init.pp @@ -174,20 +174,4 @@ # Also monitor local redis include ::redis::client::python - - $graphite_metric_prefix = "${::labsproject}.${::hostname}.reqstats" - - logster::job { 'proxy-requests': - minute => '*/1', - parser => 'LineCountLogster', # Nothing more specific yet - logfile => '/var/log/nginx/access.log', - logster_options => "-o statsd --statsd-host=labmon1001.eqiad.wmnet:8125 --metric-prefix=${graphite_metric_prefix}.all", - } - - logster::job { 'proxy-errors': - minute => '*/1', - parser => 'LineCountLogster', # Nothing more specific yet - logfile => '/var/log/nginx/error.log', - logster_options => "-o statsd --statsd-host=labmon1001.eqiad.wmnet:8125 --metric-prefix=${graphite_metric_prefix}.errors", - } } diff --git a/modules/toollabs/files/toolsweblogster.py b/modules/toollabs/files/toolsweblogster.py new file mode 100644 index 0000000..0d470c3 --- /dev/null +++ b/modules/toollabs/files/toolsweblogster.py @@ -0,0 +1,84 @@ +""" +A logster parser that tails nginx log files to count responses grouped by first segment of urls + +Examples: + 1. tools.wmflabs.org/geohack/geohack.php?x=50&y=50 + first segment: geohack + 2. tools.wmflabs.org/testtool + firstsegment: testtool + 3. tools.wmflabs.org/ + firstsegment: / + +It sends metrics of the form: + raw.{firstsegment}.status.{status} -> For statuses! + raw.{firstsegment}.httpversion.{version} -> For HTTP versions used +""" +import re + +from logster.logster_helper import MetricObject, LogsterParser +from logster.logster_helper import LogsterParsingException + + +class UrlFirstSegmentLogster(LogsterParser): + + def __init__(self, option_string=None): + '''Initialize any data structures or variables needed for keeping track + of the tasty bits we find in the log we are parsing.''' + self.status_stats = {} + self.httpver_stats = {} + # Regular expression for matching lines we are interested in, and capturing + # fields from the line (in this case, http_status_code, size and squid_code). + self.reg = re.compile(r""" + ^(?P<ip>(\d{1,3}\.?){4}) + \s-\s-\s + \[(?P<timestamp>.*)\]\s + "(?P<method>\w+)\s + /(?P<firstsegment>[^/?]+)(?P<url>/.*?) HTTP/(?P<httpversion>\d.\d)"\s + (?P<status>\d{3})\s + (?P<len>\d+)\s + "(?P<referer>.*?)"\s + "(?P<useragent>.*?)" + """, re.X) + + def parse_line(self, line): + '''This function should digest the contents of one line at a time, updating + object's state variables. Takes a single argument, the line to be parsed.''' + + # Apply regular expression to each line and extract interesting bits. + regMatch = self.reg.match(line) + + if regMatch: + bits = regMatch.groupdict() + firstsegment = bits['firstsegment'] + status = bits['status'] + httpversion = bits['httpversion'].replace('.', '_') + + statuses = self.status_stats.get(firstsegment, {status: 0}) + statuses[status] = statuses.get(status, 0) + 1 + self.status_stats[firstsegment] = statuses + + httpversions = self.httpver_stats.get(firstsegment, {httpversion: 0}) + httpversions[httpversion] = httpversions.get(httpversion, 0) + 1 + self.httpver_stats[firstsegment] = httpversions + else: + raise LogsterParsingException("regmatch failed to match") + + def get_state(self, duration): + '''Run any necessary calculations on the data collected from the logs + and return a list of metric objects.''' + + metrics = [] + for firstsegment, statuses in self.status_stats.items(): + for status, count in statuses.items(): + metric_name = 'raw.{firstsegment}.status.{status}'.format( + firstsegment=firstsegment, status=status + ) + metrics.append(MetricObject(metric_name, count, 'Responses')) + for firstsegment, httpversions in self.httpver_stats.items(): + for httpver, count in httpversions.items(): + metric_name = 'raw.{firstsegment}.httpver.{httpver}'.format( + firstsegment=firstsegment, httpver=httpver + ) + metrics.append(MetricObject(metric_name, count, 'Responses')) + + return metrics diff --git a/modules/toollabs/manifests/proxy.pp b/modules/toollabs/manifests/proxy.pp index 8f032c2..ede3fb3 100644 --- a/modules/toollabs/manifests/proxy.pp +++ b/modules/toollabs/manifests/proxy.pp @@ -96,4 +96,22 @@ } require_package('goaccess') # webserver statistics, T121233 + + $graphite_metric_prefix = "${::labsproject}.reqstats" + + file { '/usr/local/lib/python2.7/dist-packages/toolsweblogster.py': + source => 'puppet:///modules/toollabs/toolsweblogster.py', + owner => 'root', + group => 'root', + mode => '0555', + } + + logster::job { 'proxy-requests': + minute => '*/1', + parser => 'toolsweblogster.UrlFirstSegmentLogster', # Nothing more specific yet + logfile => '/var/log/nginx/access.log', + logster_options => "-o statsd --statsd-host=labmon1001.eqiad.wmnet:8125 --metric-prefix=${graphite_metric_prefix}.", + require => File['/usr/local/lib/python2.7/dist-packages/toolsweblogster.py'], + } + } -- To view, visit https://gerrit.wikimedia.org/r/300737 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ie7f35a8946a4ff7cce93396964d2c2042d8017b6 Gerrit-PatchSet: 3 Gerrit-Project: operations/puppet Gerrit-Branch: production Gerrit-Owner: Yuvipanda <yuvipa...@wikimedia.org> Gerrit-Reviewer: Yuvipanda <yuvipa...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits