apache_log_metrics: Add builder+milestone fields
This change adds a function to parse the builder and milestone
informations out of the URL string.
TEST=None
BUG=chromium:621745
Change-Id: I751e193fe86ac70dabcfd3063ab48dbaa7dcbb5d
Reviewed-on: https://chromium-review.googlesource.com/361586
Commit-Ready: Paul Hobbs <phobbs@google.com>
Tested-by: Paul Hobbs <phobbs@google.com>
Reviewed-by: Paul Hobbs <phobbs@google.com>
diff --git a/apache_log_metrics.py b/apache_log_metrics.py
index 9545fe0..0d35d09 100755
--- a/apache_log_metrics.py
+++ b/apache_log_metrics.py
@@ -25,7 +25,7 @@
STATIC_GET_MATCHER = re.compile(
r'^(?P<ip_addr>\d+\.\d+\.\d+\.\d+) '
- r'.*GET /static/\S*[^"]*" '
+ r'.*GET /static/(?P<endpoint>\S*)[^"]*" '
r'200 (?P<size>\S+) .*')
STATIC_GET_METRIC_NAME = 'chromeos/devserver/apache/static_response_size'
@@ -47,10 +47,24 @@
)
def IPToNum(ip):
- return reduce(lambda seed, x: seed * 2**8 + int(x), ip.split('.'), 0)
+ """Returns the integer represented by an IPv4 string.
+
+ Args:
+ ip: An IPv4-formatted string.
+ """
+ return reduce(lambda (seed, x): seed * 2**8 + int(x),
+ ip.split('.'),
+ 0)
def MatchesSubnet(ip, base, mask):
+ """Whether the ip string |ip| matches the subnet |base|, |mask|.
+
+ Args:
+ ip: An IPv4 string.
+ base: An IPv4 string which is the lowest value in the subnet.
+ mask: The number of bits which are not wildcards in the subnet.
+ """
ip_value = IPToNum(ip)
base_value = IPToNum(base)
mask = (2**mask - 1) << (32 - mask)
@@ -58,27 +72,70 @@
def InLab(ip):
+ """Whether |ip| is an IPv4 address which is in the ChromeOS Lab.
+
+ Args:
+ ip: An IPv4 address to be tested.
+ """
return any(MatchesSubnet(ip, base, mask)
for (base, mask) in LAB_SUBNETS)
-def EmitStaticRequestMetric(m):
- """Emits a Counter metric for sucessful GETs to /static endpoints."""
- ipaddr, size = m.groups()
+def ParseStaticEndpoint(endpoint):
+ """Parses a /static/.* URL path into build_config, milestone, and filename.
+
+ Static endpoints are expected to be of the form
+ /static/$BUILD_CONFIG/$MILESTONE-$VERSION/$FILENAME
+
+ This function expects the '/static/' prefix to already be stripped off.
+
+ Args:
+ endpoint: A string which is the matched URL path after /static/
+ """
+ build_config, milestone, filename = [''] * 3
try:
- size = int(size)
+ parts = endpoint.split('/')
+ build_config = parts[0]
+ if len(parts) >= 2:
+ version = parts[1]
+ milestone = version[:version.index('-')]
+ if len(parts) >= 3:
+ filename = parts[-1]
+ except IndexError as e:
+ logging.debug('%s failed to parse. Caught %s' % (endpoint, str(e)))
+
+ return build_config, milestone, filename
+
+
+def EmitStaticRequestMetric(m):
+ """Emits a Counter metric for sucessful GETs to /static endpoints.
+
+ Args:
+ m: A regex match object
+ """
+ build_config, milestone, filename = ParseStaticEndpoint(m.group('endpoint'))
+
+ try:
+ size = int(m.group('size'))
except ValueError: # Zero is represented by "-"
size = 0
metrics.Counter(STATIC_GET_METRIC_NAME).increment_by(
size, fields={
- 'builder': '',
- 'in_lab': InLab(ipaddr),
- 'endpoint': ''})
+ 'build_config': build_config,
+ 'milestone': milestone,
+ 'in_lab': InLab(m.group('ipaddr')),
+ 'endpoint': filename})
def RunMatchers(stream, matchers):
- """Parses lines of |stream| using patterns and emitters from |matchers|"""
+ """Parses lines of |stream| using patterns and emitters from |matchers|
+
+ Args:
+ stream: A file object to read from.
+ matchers: A list of pairs of (matcher, emitter), where matcher is a regex
+ and emitter is a function called when the regex matches.
+ """
for line in iter(stream.readline, ''):
for matcher, emitter in matchers:
logging.debug('Emitting %s for input "%s"',