Add application-insights debug cli (#281)

This commit is contained in:
bmc-msft
2020-11-11 06:17:43 -05:00
committed by GitHub
parent daba3232bc
commit e638908aac
6 changed files with 109 additions and 1 deletions

View File

@ -9,6 +9,7 @@ from onefuzztypes.responses import Info
from ..onefuzzlib.azure.creds import ( from ..onefuzzlib.azure.creds import (
get_base_region, get_base_region,
get_base_resource_group, get_base_resource_group,
get_insights_appid,
get_instance_id, get_instance_id,
get_subscription, get_subscription,
) )
@ -24,5 +25,6 @@ def main(req: func.HttpRequest) -> func.HttpResponse:
subscription=get_subscription(), subscription=get_subscription(),
versions=versions(), versions=versions(),
instance_id=get_instance_id(), instance_id=get_instance_id(),
insights_appid=get_insights_appid(),
) )
) )

View File

@ -82,6 +82,11 @@ def get_subscription() -> Any: # should be str
return parse_resource_id(os.environ["ONEFUZZ_DATA_STORAGE"])["subscription"] return parse_resource_id(os.environ["ONEFUZZ_DATA_STORAGE"])["subscription"]
@cached
def get_insights_appid() -> str:
return os.environ["APPINSIGHTS_APPID"]
@cached @cached
def get_fuzz_storage() -> str: def get_fuzz_storage() -> str:
return os.environ["ONEFUZZ_DATA_STORAGE"] return os.environ["ONEFUZZ_DATA_STORAGE"]

View File

@ -3,15 +3,19 @@
# Copyright (c) Microsoft Corporation. # Copyright (c) Microsoft Corporation.
# Licensed under the MIT License. # Licensed under the MIT License.
import json
import logging import logging
import os import os
import shutil import shutil
import subprocess # nosec import subprocess # nosec
import tempfile import tempfile
from typing import Any, List, Optional, Tuple from typing import Any, Dict, List, Optional, Tuple
from urllib.parse import urlparse from urllib.parse import urlparse
from uuid import UUID from uuid import UUID
from azure.applicationinsights import ApplicationInsightsDataClient
from azure.applicationinsights.models import QueryBody
from azure.common.client_factory import get_azure_cli_credentials
from onefuzztypes.enums import ContainerType, TaskType from onefuzztypes.enums import ContainerType, TaskType
from onefuzztypes.models import BlobRef, NodeAssignment, Report, Task from onefuzztypes.models import BlobRef, NodeAssignment, Report, Task
from onefuzztypes.primitives import Directory from onefuzztypes.primitives import Directory
@ -262,6 +266,94 @@ class DebugJob(Command):
subprocess.check_output([azcopy, "sync", to_download[name], outdir]) subprocess.check_output([azcopy, "sync", to_download[name], outdir])
class DebugLog(Command):
def _convert(self, raw_data: Any) -> Dict[str, List[Dict[str, Any]]]:
results = {}
for table in raw_data.tables:
result = []
for row in table.rows:
converted = {
table.columns[x].name: y
for (x, y) in enumerate(row)
if y not in [None, ""]
}
if "customDimensions" in converted:
converted["customDimensions"] = json.loads(
converted["customDimensions"]
)
result.append(converted)
results[table.name] = result
return results
def query(
self, log_query: str, *, timespan: str = "PT24H", raw: bool = False
) -> Any:
"""
Perform an Application Insights query
Queries should be well formed Kusto Queries.
Ref https://docs.microsoft.com/en-us/azure/data-explorer/kql-quick-reference
:param str log_query: Query to send to Application Insights
:param str timespan: ISO 8601 duration format
:param bool raw: Do not simplify the data result
"""
creds, _ = get_azure_cli_credentials(
resource="https://api.applicationinsights.io"
)
client = ApplicationInsightsDataClient(creds)
app_id = self.onefuzz.info.get().insights_appid
if app_id is None:
raise Exception("instance does not have an insights_appid")
raw_data = client.query.execute(
app_id, body=QueryBody(query=log_query, timespan=timespan)
)
if "error" in raw_data.additional_properties:
raise Exception(
"Error performing query: %s" % raw_data.additional_properties["error"]
)
if raw:
return raw_data
return self._convert(raw_data)
def keyword(
self,
value: str,
*,
timespan: str = "PT24H",
limit: Optional[int] = None,
raw: bool = False,
) -> Any:
"""
Perform an Application Insights keyword query akin to "Transaction Search"
:param str value: Keyword to query Application Insights
:param str timespan: ISO 8601 duration format
:param int limit: Limit the number of records returned
:param bool raw: Do not simplify the data result
"""
# See https://docs.microsoft.com/en-us/azure/data-explorer/kql-quick-reference
components = ["union isfuzzy=true exceptions, traces, customEvents"]
value = value.strip()
keywords = ['* has "%s"' % (x.replace('"', '\\"')) for x in value.split(" ")]
if keywords:
components.append("where " + " and ".join(keywords))
components.append("order by timestamp desc")
if limit is not None:
components.append(f"take {limit}")
log_query = " | ".join(components)
self.logger.debug("query: %s", log_query)
return self.query(log_query, timespan=timespan)
class DebugNotification(Command): class DebugNotification(Command):
""" Debug notification integrations """ """ Debug notification integrations """
@ -366,3 +458,4 @@ class Debug(Command):
self.job = DebugJob(onefuzz, logger) self.job = DebugJob(onefuzz, logger)
self.notification = DebugNotification(onefuzz, logger) self.notification = DebugNotification(onefuzz, logger)
self.task = DebugTask(onefuzz, logger) self.task = DebugTask(onefuzz, logger)
self.logs = DebugLog(onefuzz, logger)

View File

@ -8,7 +8,10 @@ asciimatics~=1.11.0
dataclasses~=0.6 dataclasses~=0.6
pydantic~=1.6.1 --no-binary=pydantic pydantic~=1.6.1 --no-binary=pydantic
memoization~=0.3.1 memoization~=0.3.1
msrestazure==0.6.4
azure-storage-blob~=12.3 azure-storage-blob~=12.3
azure-applicationinsights==0.1.0
adal~=1.2.5
tenacity==6.2.0 tenacity==6.2.0
docstring_parser==0.7.3 docstring_parser==0.7.3
# onefuzztypes version is set during build # onefuzztypes version is set during build

View File

@ -161,6 +161,10 @@
"name": "APPINSIGHTS_INSTRUMENTATIONKEY", "name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(resourceId('microsoft.insights/components/', parameters('name')), '2015-05-01').InstrumentationKey]" "value": "[reference(resourceId('microsoft.insights/components/', parameters('name')), '2015-05-01').InstrumentationKey]"
}, },
{
"name": "APPINSIGHTS_APPID",
"value": "[reference(resourceId('microsoft.insights/components/', parameters('name')), '2015-05-01').AppId]"
},
{ {
"name": "ONEFUZZ_TELEMETRY", "name": "ONEFUZZ_TELEMETRY",
"value": "[variables('telemetry')]" "value": "[variables('telemetry')]"

View File

@ -37,6 +37,7 @@ class Info(BaseResponse):
subscription: str subscription: str
versions: Dict[str, Version] versions: Dict[str, Version]
instance_id: Optional[UUID] instance_id: Optional[UUID]
insights_appid: Optional[str]
class ContainerInfoBase(BaseResponse): class ContainerInfoBase(BaseResponse):