mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-17 04:18:07 +00:00
Add application-insights debug cli (#281)
This commit is contained in:
@ -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(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -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"]
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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')]"
|
||||||
|
@ -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):
|
||||||
|
Reference in New Issue
Block a user