-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce new, more performant implementation
- Loading branch information
Showing
7 changed files
with
739 additions
and
8 deletions.
There are no files selected for viewing
354 changes: 351 additions & 3 deletions
354
win32_event_log/datadog_checks/win32_event_log/check.py
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# (C) Datadog, Inc. 2020-present | ||
# All rights reserved | ||
# Licensed under a 3-clause BSD style license (see LICENSE) | ||
try: | ||
from datadog_agent import read_persistent_cache, write_persistent_cache | ||
except ImportError: | ||
|
||
def write_persistent_cache(key, value): | ||
pass | ||
|
||
def read_persistent_cache(key): | ||
return '' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
103 changes: 103 additions & 0 deletions
103
win32_event_log/datadog_checks/win32_event_log/filters.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
# (C) Datadog, Inc. 2020-present | ||
# All rights reserved | ||
# Licensed under a 3-clause BSD style license (see LICENSE) | ||
from collections import OrderedDict | ||
|
||
|
||
def construct_xpath_query(filters): | ||
if not filters: | ||
return '*' | ||
|
||
node_tree = OrderedDict({'*': OrderedDict()}) | ||
|
||
for node_path, values in filters.items(): | ||
# We make `tree` reference the root of the tree | ||
# at every iteration to create the new branches. | ||
tree = node_tree['*'] | ||
|
||
# Separate each full path into its constituent nodes. | ||
parts = node_path.split('.') | ||
|
||
# Recurse through all but the last node. | ||
for part in parts[:-1]: | ||
# Create branch if necessary. | ||
if part not in tree: | ||
tree[part] = OrderedDict() | ||
|
||
# Move to the next branch. | ||
tree = tree[part] | ||
|
||
# Set the final branch to the user-defined values. | ||
if values: | ||
tree[parts[-1]] = values | ||
# Users can define no values (indicating the mere presence of elements) with an empty list or mapping. | ||
# However, the parser assumes that values are always lists for simplicity. | ||
else: | ||
tree[parts[-1]] = [] | ||
|
||
parts = [] | ||
accumulate_query_parts(parts, node_tree) | ||
|
||
return ''.join(parts) | ||
|
||
|
||
def accumulate_query_parts(parts, node_tree): | ||
# Due to time constraints, this here is an ugly parser. A cookie shall be given to the one who makes it beautiful. | ||
# | ||
# Here are a bunch of examples of XPath queries: | ||
# - https://powershell.org/2019/08/a-better-way-to-search-events/ | ||
# - https://www.petri.com/query-xml-event-log-data-using-xpath-in-windows-server-2012-r2 | ||
# - https://blog.backslasher.net/filtering-windows-event-log-using-xpath.html | ||
for node, values in node_tree.items(): | ||
# Recursively walk the tree | ||
if isinstance(values, OrderedDict): | ||
if parts and parts[-1] == ']': | ||
parts.append(' and ') | ||
|
||
parts.append(node) | ||
parts.append('[') | ||
accumulate_query_parts(parts, values) | ||
|
||
# Catch erroneous operator | ||
if parts[-1] == ' and ': | ||
parts.pop() | ||
|
||
# Detect premature closures | ||
if parts[-1] is None: | ||
parts.pop() | ||
else: | ||
parts.append(']') | ||
|
||
# Finished branch | ||
else: | ||
if values: | ||
if parts and parts[-1] == ')': | ||
parts.append(' and ') | ||
|
||
if node.startswith('@'): | ||
parts.append(node) | ||
parts.append(']=') | ||
parts.append(value_to_xpath_string(values[0])) | ||
|
||
# Indicate to the tree walker that we already closed the node | ||
parts.append(None) | ||
else: | ||
parts.append('(') | ||
parts.append(' or '.join('{}={}'.format(node, value_to_xpath_string(value)) for value in values)) | ||
parts.append(')') | ||
else: | ||
if parts and parts[-1] == ']': | ||
parts.append(' and ') | ||
|
||
parts.append(node) | ||
|
||
# Always assume more clauses and let tree walker catch errors | ||
parts.append(' and ') | ||
|
||
|
||
def value_to_xpath_string(value): | ||
# Most sources indicate single quotes are preferred, I cannot find an official directive | ||
if isinstance(value, str): | ||
return "'{}'".format(value) | ||
|
||
return str(value) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# (C) Datadog, Inc. 2020-present | ||
# All rights reserved | ||
# Licensed under a 3-clause BSD style license (see LICENSE) | ||
import win32api | ||
|
||
|
||
def get_last_error_message(): | ||
""" | ||
Helper function to get the error message from the calling thread's most recently failed operation. | ||
It appears that in most cases pywin32 catches such failures and raises Python exceptions. | ||
""" | ||
# https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror | ||
# https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessage | ||
# http://timgolden.me.uk/pywin32-docs/win32api__FormatMessage_meth.html | ||
return win32api.FormatMessage(0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
lxml==4.5.0 | ||
pywin32==227; sys_platform == 'win32' | ||
uptime==3.0.1 |
Oops, something went wrong.