Search the Audit Log
Review the steps to search the Audit Log
Use the following ways to search the Audit Log.
Perform a search via the SDK
Each SDK provides a search
method that can be used to search the audit log.
The following shows an example of searching the audit logs.
import os
import pangea.exceptions as pe
from pangea.config import PangeaConfig
from pangea.response import PangeaResponse
from pangea.services import Audit
from pangea.services.audit.audit import SearchOutput, SearchResultOutput
from pangea.tools import logger_set_pangea_config
# This example shows how to perform an audit log, and then search for thats results
token = os.getenv("PANGEA_AUDIT_TOKEN")
domain = os.getenv("PANGEA_DOMAIN")
config = PangeaConfig(domain=domain)
audit = Audit(token, config=config, private_key_file="./key/privkey", logger_name="audit")
logger_set_pangea_config(logger_name=audit.logger.name)
def main():
print("Log Data...")
msg = "python-sdk-standard-schema-example"
try:
log_response = audit.log(
message=msg,
actor="Someone",
action="Testing",
source="monitor",
status="Good",
target="Another spot",
new="New updated message",
old="Old message that it's been updated",
verify=True,
verbose=False,
sign_local=True,
)
print(f"Log Request ID: {log_response.request_id}, Status: {log_response.status}")
except pe.PangeaAPIException as e:
print(f"Request Error: {e.response.summary}")
for err in e.errors:
print(f"\t{err.detail} \n")
exit()
print("Search Data...")
page_size = 10
query = "message:" + msg
try:
search_res: PangeaResponse[SearchOutput] = audit.search(
query=query, limit=page_size, verify_consistency=True, verify_events=True
)
result_id = search_res.result.id
count = search_res.result.count
print(f"Search Request ID: {search_res.request_id}, Success: {search_res.status}, Results: {count}")
offset = 0
print_header_results()
while offset < count:
print_page_results(search_res, offset, count)
offset += page_size
if offset < count:
search_res = audit.results(
id=result_id, limit=page_size, offset=offset, verify_consistency=True, verify_events=True
)
except pe.PangeaAPIException as e:
print("Search Failed:", e.response.summary)
for err in e.errors:
print(f"\t{err.detail} \n")
def print_header_results():
print(f"\n\nreceived_at\t\t\t\tMessage \tSource " f"\t\tActor \t\tMembership \tConsistency \tSignature\t")
def print_page_results(search_res: PangeaResponse[SearchResultOutput], offset, count):
print("\n--------------------------------------------------------------------\n")
for row in search_res.result.events:
print(
f"{row.envelope.received_at}\t{row.envelope.event['message']}\t{row.envelope.event['source']}\t\t"
f"{row.envelope.event['actor']}\t\t{row.membership_verification}\t\t {row.consistency_verification}\t\t {row.signature_verification}\t\t"
)
print(
f"\nResults: {offset+1}-{offset+len(search_res.result.events)} of {count}",
)
if __name__ == "__main__":
main()
Setting the optional parameter verify
to true will automatically verify the membership and consistency proofs of each returned result.
Paginate search results
Audit results can be paginated using a combination of offset
, count
, and results_id
. The results_id
is returned by the search method and is a unique id corresponding to the search results. Search results don't live indefinitely; they have a defined expiration date that's also returned with the search results. Offset
is used to determine at which record number results should be returned, and Count
indicates how many records in total have been returned by the search. Continuing the previous example, paging through the results would look like this:
if search_res.success:
result_id = search_res.result.id
count = search_res.result.count
offset = 0
while offset < count and search_res.success:
for row in search_res.result.events:
print(f"{row.event.received_at}\t{row.event.message}\t{row.event.source}")
offset += page_size
search_res = audit.results(result_id, limit=page_size, offset=offset)
Restrict search results
In some cases, it may be desirable to partition search results. The search_restriction
provided as restriction
to the Python SDK can facilitate this need. A search_restriction
can limit queries to the data described by the search restriction.
As an example, consider the following restriction:
{
"actor":"Dennis Nedry"
}
In this case, no matter the results included in the query, only results containing "Dennis Nedry" in the actor
field will be returned.
This could be useful in an app that exposes the search interface to its users, providing the users with a way to search for auditable actions performed by themselves. A search restriction could restrict them to such actions without allowing them to see activities performed by other users.
Search syntax
The Search capability provides a simple search grammar to use when searching the logs for specific events.
The search queries are case sensitive.
Simple search
The search query can be provided as either key-value pairs to specify searching for the query text in a specific field or just the query text to search for the text across all audit fields. For example, a query of deactivated
will search for the term deactivated
across all fields.
Single field search
A simple search string should be provided as <field_name>:<value>
. The field name should be an exact match of the field name to be searched. The /search
API will perform a partial match of data in the specified field matching the search term.
For example: actor:"Dennis"
will initiate the search for any audit event where the actor
field contains the word Dennis
.
You can exclude specific values and return everything that does not match the search term by including a minus (-) prefix. For example, -actor:"Dennis"
returns all results where the actor
field does not include the word Dennis
.
Certain field types, including integers, booleans, and datetimes (in the case of Custom schemas), offer the following functionalities:
- Comparison operators: For fields that support comparison (like datetime and integer), you can use
>
or<
instead of:
to compare values that are greater than or less than the second part, respectively. For example, ifvalue
is a field in your schema, bothvalue>10
andvalue<10
are valid expressions. - Negative values: For integer fields, you can add minus (-) prefix to the number. For example,
value<-11
would search for everything with a value less than negative 11. - Boolean field filtering: You can filter boolean fields using
fieldname:true
to find values that aretrue
orfieldname:false
to locate values that arefalse
.
Using multiple search terms
Multiple search terms can be joined using the AND
and OR
operators. For example, to search for events where the actor
field contains Dennis
and the target
contains Security
, the following search string would be used:
actor:"Dennis" AND target:"Security"
Grouping search terms
Search terms can be logically grouped using parentheses. As an example, to search for events where the actor is "Dennis" or "Grant" and the target is "Security" the following would be used:
(actor:"Dennis" OR target:"Grant") AND target "Security"
Was this article helpful?