Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[docker] Filter events #1285

Merged
merged 6 commits into from
Jan 13, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 43 additions & 18 deletions checks.d/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,11 @@ def check(self, instance):
containers, ids_to_names = self._get_and_count_containers(instance)

# Report container metrics from cgroups
self._report_containers_metrics(containers, instance)
skipped_container_ids = self._report_containers_metrics(containers, instance)

# Send events from Docker API
if instance.get('collect_events', True):
self._process_events(instance, ids_to_names)
self._process_events(instance, ids_to_names, skipped_container_ids)


# Containers
Expand Down Expand Up @@ -188,23 +188,39 @@ def _get_and_count_containers(self, instance):

return running_containers, ids_to_names

def _is_container_included(self, instance, tags):
def _is_tag_included(tag):
for exclude_rule in instance.get("exclude") or []:
if re.match(exclude_rule, tag):
for include_rule in instance.get("include") or []:
if re.match(include_rule, tag):
return True
return False
def _prepare_filters(self, instance):
# The reasoning is to check exclude first, so we can skip if there is no exclude
if not instance.get("exclude"):
return False

# Compile regex
instance["exclude_patterns"] = [re.compile(rule) for rule in instance.get("exclude", [])]
instance["include_patterns"] = [re.compile(rule) for rule in instance.get("include", [])]

return True

def _is_container_excluded(self, instance, tags):
if self._tags_match_patterns(tags, instance.get("exclude_patterns")):
if self._tags_match_patterns(tags, instance.get("include_patterns")):
return False
return True
for tag in tags:
if _is_tag_included(tag):
return True
return False

def _tags_match_patterns(self, tags, filters):
for rule in filters:
for tag in tags:
if re.match(rule, tag):
return True
return False

def _report_containers_metrics(self, containers, instance):
skipped_container_ids = []
collect_uncommon_metrics = instance.get("collect_all_metrics", False)
tags = instance.get("tags", [])

# Pre-compile regex to include/exclude containers
use_filters = self._prepare_filters(instance)

for container in containers:
container_tags = list(tags)
for name in container["Names"]:
Expand All @@ -215,7 +231,8 @@ def _report_containers_metrics(self, containers, instance):
container_tags.append(tag)

# Check if the container is included/excluded via its tags
if not self._is_container_included(instance, container_tags):
if use_filters and self._is_container_excluded(instance, container_tags):
skipped_container_ids.append(container['Id'])
continue

for key, (dd_key, metric_type) in DOCKER_METRICS.iteritems():
Expand All @@ -228,9 +245,12 @@ def _report_containers_metrics(self, containers, instance):
for key, (dd_key, metric_type, common_metric) in cgroup['metrics'].iteritems():
if key in stats and (common_metric or collect_uncommon_metrics):
getattr(self, metric_type)(dd_key, int(stats[key]), tags=container_tags)
if use_filters:
self.log.debug("List of excluded containers: {0}".format(skipped_container_ids))

def _make_tag(self, key, value, instance):
return skipped_container_ids

def _make_tag(self, key, value, instance):
tag_name = key.lower()
if tag_name == "command" and not instance.get("tag_by_command", False):
return None
Expand All @@ -246,19 +266,24 @@ def _new_tags_conversion(self, tag):

# Events

def _process_events(self, instance, ids_to_names):
def _process_events(self, instance, ids_to_names, skipped_container_ids):
try:
api_events = self._get_events(instance)
aggregated_events = self._pre_aggregate_events(api_events)
aggregated_events = self._pre_aggregate_events(api_events, skipped_container_ids)
events = self._format_events(aggregated_events, ids_to_names)
self._report_events(events)
except (socket.timeout, urllib2.URLError):
self.warning('Timeout during socket connection. Events will be missing.')

def _pre_aggregate_events(self, api_events):
def _pre_aggregate_events(self, api_events, skipped_container_ids):
# Aggregate events, one per image. Put newer events first.
events = defaultdict(list)
for event in api_events:
# Skip events related to filtered containers
if event['id'] in skipped_container_ids:
self.log.debug("Excluded event: container {0} status changed to {1}".format(
event['id'], event['status']))
continue
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick but let's log something in debug here.

# Known bug: from may be missing
if 'from' in event:
events[event['from']].insert(0, event)
Expand Down
20 changes: 11 additions & 9 deletions conf.d/docker.yaml.example
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,26 @@ instances:
# Example:
# tags: ["extra_tag", "env:example"]

# To include or exclude containers based on their tags, use the include and
# exclude keys in your instance.
# The reasoning is: if a tag matches an exclude rule, it won't be included
# unless it also matches an include rule.
# Exclude containers based on their tags
# An excluded container will ne longer report performance metrics or events. However,
# we still count the number of running and stopped of all containers.
#
# How it works: if a tag matches an exclude rule, it won't be included
# unless it also matches an include rule.
# Examples:
#
# exclude all, except ubuntu and debian.
# include:
# - "image:ubuntu"
# - "image:debian"
# - "docker_image:ubuntu"
# - "docker_image:debian"
# exclude:
# - ".*"
#
# include all, except ubuntu and debian.
# include: []
# exclude:
# - "image:ubuntu"
# - "image:debian"
# - "docker_image:ubuntu"
# - "docker_image:debian"
#
# include: []
# exclude: []
Expand All @@ -55,7 +56,8 @@ instances:
# collect_events: true

# Collect disk usage per container with docker.disk.size metric.
# Warning: Some bugs in Docker (especially Docker 1.2) can break it, use with caution.
# Warning: This feature is broken in some version of Docker (such as 1.2).
# Test it before running it in production.
#
# collect_container_size: false

Expand Down