{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.24.24.22086", "templateHash": "1472628451461453644" } }, "parameters": { "aiServiceApiBase": { "type": "string", "metadata": { "description": "URL of the AI Service API" } }, "gechologApiKey": { "type": "securestring", "defaultValue": "", "metadata": { "description": "OPTIONAL: ingress API Key for the /restricted/ router" } }, "aiServiceApiKey": { "type": "securestring", "defaultValue": "", "metadata": { "description": "OPTIONAL: outbound API Key for /restricted/ router" } }, "natsToken": { "type": "securestring", "defaultValue": "", "metadata": { "description": "OPTIONAL: nats token" } }, "guiSecret": { "type": "securestring", "defaultValue": "", "metadata": { "description": "OPTIONAL: gui secret" } }, "guiPort": { "type": "int", "defaultValue": 80, "metadata": { "description": "OPTIONAL: gui port (set to 8080 to enable GUI)" } }, "storageAccountName": { "type": "string", "defaultValue": "gechologstorage", "metadata": { "description": "Storage Account Name" } }, "confFileShareName": { "type": "string", "defaultValue": "conf", "metadata": { "description": "Config file share" } }, "logFileShareName": { "type": "string", "defaultValue": "log", "metadata": { "description": "Log file share" } }, "logSpaceName": { "type": "string", "defaultValue": "gechologspace", "metadata": { "description": "Log Space name" } }, "sku": { "type": "string", "defaultValue": "PerGB2018", "metadata": { "description": "sku" } }, "containerGroupName": { "type": "string", "defaultValue": "gecholog", "metadata": { "description": "Name for the container group" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources." } }, "image": { "type": "string", "defaultValue": "gecholog/gecholog:latest", "metadata": { "description": "Container image to deploy. Should be of the form repoName/imagename:tag for images stored in public Docker Hub, or a fully qualified URI for other registries. Images from private registries require additional registry credentials." } }, "nats2logLoggerSubTopic": { "type": "string", "defaultValue": ".logger", "metadata": { "description": "Set to .logger to activate nats2log" } }, "nats2fileLoggerSubTopic": { "type": "string", "defaultValue": ".logger", "metadata": { "description": "Set to .logger to activate nats2file" } }, "dnsLabel": { "type": "string", "defaultValue": "gecholog", "metadata": { "description": "DNS name prefix label for used to create FQDN" } }, "port": { "type": "int", "defaultValue": 5380, "metadata": { "description": "Port to open on the container and the public IP address." } }, "cpuCores": { "type": "int", "defaultValue": 1, "metadata": { "description": "The number of CPU cores to allocate to the container." } }, "memoryInGb": { "type": "int", "defaultValue": 1, "metadata": { "description": "The amount of memory to allocate to the container in gigabytes." } }, "workbookId": { "type": "string", "defaultValue": "[newGuid()]", "metadata": { "description": "The unique guid for the workbook instance" } }, "restartPolicy": { "type": "string", "defaultValue": "Always", "allowedValues": [ "Always", "Never", "OnFailure" ], "metadata": { "description": "The behavior of Azure runtime if container has stopped." } } }, "variables": { "uniqueStr": "[uniqueString(resourceGroup().id)]", "dnsNameLabelUnique": "[format('{0}-{1}', parameters('dnsLabel'), variables('uniqueStr'))]", "workbookDisplayName": "gecholog Dashboard DevOps", "workbookType": "workbook", "rawSerializedDataStr": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"# Gecholog Analytics Workbook - Visit our docs site [docs.gecholog.ai](https://docs.gecholog.ai)\",\"style\":\"upsell\"},\"name\":\"text - 8\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"parameters\":[{\"id\":\"95510b98-7196-47c1-b082-8fdbcea7a135\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"columnFilter\",\"type\":2,\"isRequired\":true,\"query\":\"gecholog_CL\\n| getschema\\n| distinct ColumnName\",\"typeSettings\":{\"additionalResourceOptions\":[\"value::1\"],\"showDefault\":false},\"timeContext\":{\"durationMs\":86400000},\"defaultValue\":\"value::1\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"value\":\"request_gl_path_s\"},{\"id\":\"6a5f1484-a964-4597-9390-9b9f8dadd238\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"ingressStartTime\",\"type\":4,\"isRequired\":true,\"typeSettings\":{\"selectableValues\":[{\"durationMs\":300000},{\"durationMs\":900000},{\"durationMs\":1800000},{\"durationMs\":3600000},{\"durationMs\":14400000},{\"durationMs\":43200000},{\"durationMs\":86400000},{\"durationMs\":172800000},{\"durationMs\":259200000},{\"durationMs\":604800000},{\"durationMs\":1209600000},{\"durationMs\":2419200000},{\"durationMs\":2592000000},{\"durationMs\":5184000000},{\"durationMs\":7776000000}],\"allowCustom\":true},\"timeContext\":{\"durationMs\":86400000},\"value\":{\"durationMs\":14400000}}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"Gecholog Parameters\"},{\"type\":1,\"content\":{\"json\":\"# Traffic Analysis\",\"style\":\"info\"},\"name\":\"text - 18\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let columnName = '{columnFilter}'; // Use the workbook parameter\\nlet start_time = todatetime('{ingressStartTime:startISO}'); // Use the workbook parameter\\nlet end_time = todatetime('{ingressStartTime:endISO}'); // Use the workbook parameter\\nlet findIngressStartTimeStamp = (t:datetime, s:string) { // We don't trust the log analytics indexing\\n coalesce(t, todatetime(s))\\n};\\ngecholog_CL\\n| extend ingressStartTimeStamp = findIngressStartTimeStamp(column_ifexists('ingress_egress_timer_start_t', datetime(null)), ingress_egress_timer_start_s)\\n| where ingressStartTimeStamp >= start_time and ingressStartTimeStamp <= end_time\\n| extend DynamicColumn = coalesce(column_ifexists(columnName, \\\"\\\"), \\\"NaN\\\")\\n| summarize Count = count() by Bin = bin(ingressStartTimeStamp, (end_time - start_time) / 50), DynamicColumn\\n| order by Bin asc, DynamicColumn\\n| render columnchart with (series = DynamicColumn)\\n\\n\",\"size\":0,\"title\":\"Count Histogram\",\"timeContextFromParameter\":\"ingressStartTime\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"graphSettings\":{\"type\":0}},\"name\":\"Count Histogram\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let columnName = '{columnFilter}'; // Use the workbook parameter\\nlet start_time = todatetime('{ingressStartTime:startISO}'); // Use the workbook parameter\\nlet end_time = todatetime('{ingressStartTime:endISO}'); // Use the workbook parameter\\nlet findIngressStartTimeStamp = (t:datetime, s:string) { // We don't trust the log analytics indexing\\n coalesce(t, todatetime(s))\\n};\\ngecholog_CL\\n| extend ingressStartTimeStamp = findIngressStartTimeStamp(column_ifexists('ingress_egress_timer_start_t', datetime(null)), ingress_egress_timer_start_s)\\n| where ingressStartTimeStamp >= start_time and ingressStartTimeStamp <= end_time\\n| extend DynamicColumn = coalesce(column_ifexists(columnName, \\\"\\\"), \\\"NaN\\\")\\n| summarize Count = count(),\\n TotalTokens = round(sum(response_token_count_total_tokens_d), 1), \\n AverageTokens = round(avg(response_token_count_total_tokens_d), 1),\\n PromptTokens = round(sum(response_token_count_prompt_tokens_d), 1), \\n CompletionTokens = round(sum(response_token_count_completion_tokens_d), 1), \\n AverageDuration = round(avg(ingress_egress_timer_duration_d), 1),\\n StatusCodeNotOK = countif(response_egress_status_code_d != 200)\\n by DynamicColumn\\n| order by DynamicColumn\\n\",\"size\":1,\"title\":\"Table of Statistics\",\"timeContextFromParameter\":\"ingressStartTime\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"customWidth\":\"75\",\"name\":\"Table of Statistics\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let columnName = '{columnFilter}'; // Use the workbook parameter\\nlet start_time = todatetime('{ingressStartTime:startISO}'); // Use the workbook parameter\\nlet end_time = todatetime('{ingressStartTime:endISO}'); // Use the workbook parameter\\nlet findIngressStartTimeStamp = (t:datetime, s:string) { // We don't trust the log analytics indexing\\n coalesce(t, todatetime(s))\\n};\\ngecholog_CL\\n| extend ingressStartTimeStamp = findIngressStartTimeStamp(column_ifexists('ingress_egress_timer_start_t', datetime(null)), ingress_egress_timer_start_s)\\n| where ingressStartTimeStamp >= start_time and ingressStartTimeStamp <= end_time\\n| extend DynamicColumn = coalesce(column_ifexists(columnName, \\\"\\\"), \\\"NaN\\\")\\n| summarize Count = count() by DynamicColumn\\n| render piechart\\n\",\"size\":3,\"title\":\"Share of API Calls\",\"timeContextFromParameter\":\"ingressStartTime\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"customWidth\":\"25\",\"name\":\"query - 5\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let columnName = '{columnFilter}'; // Use the workbook parameter\\nlet start_time = todatetime('{ingressStartTime:startISO}'); // Use the workbook parameter\\nlet end_time = todatetime('{ingressStartTime:endISO}'); // Use the workbook parameter\\nlet findIngressStartTimeStamp = (t:datetime, s:string) { // We don't trust the log analytics indexing\\n coalesce(t, todatetime(s))\\n};\\ngecholog_CL\\n| extend ingressStartTimeStamp = findIngressStartTimeStamp(column_ifexists('ingress_egress_timer_start_t', datetime(null)), ingress_egress_timer_start_s)\\n| where ingressStartTimeStamp >= start_time and ingressStartTimeStamp <= end_time\\n| extend DynamicColumn = coalesce(column_ifexists(columnName, \\\"\\\"), \\\"NaN\\\")\\n| summarize arg_max(ingressStartTimeStamp, *) by DynamicColumn\\n| project \\n DynamicColumn,\\n LastTransactionId = transaction_id_s, \\n LastSessionId = session_id_s,\\n LastTime = ingressStartTimeStamp,\\n LastTotalTokens = response_token_count_total_tokens_d,\\n LastDuration = ingress_egress_timer_duration_d,\\n StatusCode = response_egress_status_code_d\\n| order by DynamicColumn\\n\",\"size\":1,\"title\":\"Last Transaction\",\"timeContextFromParameter\":\"ingressStartTime\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"Last Transaction\"},{\"type\":1,\"content\":{\"json\":\"# Performance\",\"style\":\"info\"},\"name\":\"text - 22\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let columnName = '{columnFilter}'; // Use the workbook parameter\\nlet start_time = todatetime('{ingressStartTime:startISO}'); // Use the workbook parameter\\nlet end_time = todatetime('{ingressStartTime:endISO}'); // Use the workbook parameter\\nlet findIngressStartTimeStamp = (t:datetime, s:string) { // We don't trust the log analytics indexing\\n coalesce(t, todatetime(s))\\n};\\ngecholog_CL\\n| extend ingressStartTimeStamp = findIngressStartTimeStamp(column_ifexists('ingress_egress_timer_start_t', datetime(null)), ingress_egress_timer_start_s)\\n| where ingressStartTimeStamp >= start_time and ingressStartTimeStamp <= end_time\\n| extend DynamicColumn = column_ifexists(columnName, \\\"\\\")\\n| summarize TotalTokenConsumption = sum(response_token_count_total_tokens_d) by Bin = bin(ingressStartTimeStamp, (end_time - start_time) / 50), DynamicColumn\\n| order by Bin asc, DynamicColumn\\n| render columnchart with (series = DynamicColumn)\\n\",\"size\":0,\"title\":\"Total Token Histogram\",\"timeContextFromParameter\":\"ingressStartTime\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"Total Token Histogram\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let columnName = '{columnFilter}'; // Use the workbook parameter\\nlet start_time = todatetime('{ingressStartTime:startISO}'); // Use the workbook parameter\\nlet end_time = todatetime('{ingressStartTime:endISO}'); // Use the workbook parameter\\nlet findIngressStartTimeStamp = (t:datetime, s:string) { // We don't trust the log analytics indexing\\n coalesce(t, todatetime(s))\\n};\\ngecholog_CL\\n| extend ingressStartTimeStamp = findIngressStartTimeStamp(column_ifexists('ingress_egress_timer_start_t', datetime(null)), ingress_egress_timer_start_s)\\n| where ingressStartTimeStamp >= start_time and ingressStartTimeStamp <= end_time\\n| extend DynamicColumn = coalesce(column_ifexists(columnName, \\\"\\\"), \\\"NaN\\\")\\n| summarize AverageDuration = avg(ingress_egress_timer_duration_d) by Bin = bin(ingressStartTimeStamp, (end_time - start_time) / 50), DynamicColumn\\n| order by Bin asc, DynamicColumn\\n| render linechart with (series = DynamicColumn)\\n\",\"size\":1,\"aggregation\":3,\"title\":\"Average Duration Histogram (ms)\",\"timeContextFromParameter\":\"ingressStartTime\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"tileSettings\":{\"showBorder\":false}},\"name\":\"Average Duration Histogram (ms)\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let columnName = '{columnFilter}'; // Replace with the column name you want to analyze\\nlet start_time = todatetime('{ingressStartTime:startISO}'); // Use the workbook parameter\\nlet end_time = todatetime('{ingressStartTime:endISO}'); // Use the workbook parameter\\nlet findIngressStartTimeStamp = (t:datetime, s:string) { // We don't trust the log analytics indexing\\n coalesce(t, todatetime(s))\\n};\\nlet min_duration = toscalar(gecholog_CL | extend ingressStartTimeStamp = findIngressStartTimeStamp(column_ifexists('ingress_egress_timer_start_t', datetime(null)), ingress_egress_timer_start_s) | where ingressStartTimeStamp >= start_time and ingressStartTimeStamp <= end_time | summarize min(ingress_egress_timer_duration_d));\\nlet max_duration = toscalar(gecholog_CL | extend ingressStartTimeStamp = findIngressStartTimeStamp(column_ifexists('ingress_egress_timer_start_t', datetime(null)), ingress_egress_timer_start_s) | where ingressStartTimeStamp >= start_time and ingressStartTimeStamp <= end_time | summarize max(ingress_egress_timer_duration_d));\\ngecholog_CL\\n| extend ingressStartTimeStamp = findIngressStartTimeStamp(column_ifexists('ingress_egress_timer_start_t', datetime(null)), ingress_egress_timer_start_s)\\n| where ingressStartTimeStamp >= start_time and ingressStartTimeStamp <= end_time\\n| extend DynamicColumn = coalesce(column_ifexists(columnName, \\\"\\\"), \\\"NaN\\\")\\n| summarize Count = count() by Bin = bin(ingress_egress_timer_duration_d, (max_duration - min_duration) / 50), DynamicColumn\\n| order by Bin asc, DynamicColumn\\n| render columnchart with (series = DynamicColumn)\",\"size\":0,\"title\":\"Duration Distribution (ms)\",\"timeContextFromParameter\":\"ingressStartTime\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"Duration Distribution (ms)\"},{\"type\":1,\"content\":{\"json\":\"# Processors\",\"style\":\"info\"},\"name\":\"text - 16\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let columnName = '{columnFilter}'; // Use the workbook parameter\\nlet start_time = todatetime('{ingressStartTime:startISO}'); // Use the workbook parameter\\nlet end_time = todatetime('{ingressStartTime:endISO}'); // Use the workbook parameter\\nlet findIngressStartTimeStamp = (t:datetime, s:string) { // We don't trust the log analytics indexing\\n coalesce(t, todatetime(s))\\n};\\ngecholog_CL\\n| extend ingressStartTimeStamp = findIngressStartTimeStamp(column_ifexists('ingress_egress_timer_start_t', datetime(null)), ingress_egress_timer_start_s)\\n| where ingressStartTimeStamp >= start_time and ingressStartTimeStamp <= end_time\\n| extend DynamicColumn = coalesce(column_ifexists(columnName, \\\"\\\"), \\\"NaN\\\")\\n| project request_processors_s, DynamicColumn\\n| extend ParsedJson = parse_json(request_processors_s)\\n| mv-expand Processor = ParsedJson // Expanding the array\\n| extend processorName = tostring(Processor.name),\\n completed = tobool(Processor.details.completed),\\n duration = todouble(Processor.details.timestamp.duration)\\n| summarize countCompleted = sum(iif(completed == true, 1, 0)), \\n countNotCompleted = sum(iif(completed == false, 1, 0)), \\n averageDuration = round(avg(duration),2) by DynamicColumn, processorName\\n| order by DynamicColumn, processorName\\n\",\"size\":4,\"title\":\"Request Processor Execution\",\"timeContextFromParameter\":\"ingressStartTime\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"sortBy\":[]},\"name\":\"Request Processor Execution\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let columnName = '{columnFilter}'; // Use the workbook parameter\\nlet start_time = todatetime('{ingressStartTime:startISO}'); // Use the workbook parameter\\nlet end_time = todatetime('{ingressStartTime:endISO}'); // Use the workbook parameter\\nlet findIngressStartTimeStamp = (t:datetime, s:string) { // We don't trust the log analytics indexing\\n coalesce(t, todatetime(s))\\n};\\ngecholog_CL\\n| extend ingressStartTimeStamp = findIngressStartTimeStamp(column_ifexists('ingress_egress_timer_start_t', datetime(null)), ingress_egress_timer_start_s)\\n| where ingressStartTimeStamp >= start_time and ingressStartTimeStamp <= end_time\\n| extend DynamicColumn = coalesce(column_ifexists(columnName, \\\"\\\"), \\\"NaN\\\")\\n| project response_processors_s, DynamicColumn\\n| extend ParsedJson = parse_json(response_processors_s)\\n| mv-expand Processor = ParsedJson // Expanding the array\\n| extend processorName = tostring(Processor.name),\\n completed = tobool(Processor.details.completed),\\n duration = todouble(Processor.details.timestamp.duration)\\n| summarize countCompleted = sum(iif(completed == true, 1, 0)), \\n countNotCompleted = sum(iif(completed == false, 1, 0)), \\n averageDuration = round(avg(duration),2) by DynamicColumn, processorName\\n| order by DynamicColumn, processorName\\n\",\"size\":4,\"title\":\"Response Processors Execution\",\"timeContextFromParameter\":\"ingressStartTime\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"Response Processors Execution\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let columnName = '{columnFilter}'; // Use the workbook parameter\\nlet start_time = todatetime('{ingressStartTime:startISO}'); // Use the workbook parameter\\nlet end_time = todatetime('{ingressStartTime:endISO}'); // Use the workbook parameter\\nlet findIngressStartTimeStamp = (t:datetime, s:string) { // We don't trust the log analytics indexing\\n coalesce(t, todatetime(s))\\n};\\ngecholog_CL\\n| extend ingressStartTimeStamp = findIngressStartTimeStamp(column_ifexists('ingress_egress_timer_start_t', datetime(null)), ingress_egress_timer_start_s)\\n| where ingressStartTimeStamp >= start_time and ingressStartTimeStamp <= end_time\\n| extend DynamicColumn = coalesce(column_ifexists(columnName, \\\"\\\"), \\\"NaN\\\")\\n| project request_processors_async_s, DynamicColumn\\n| extend ParsedJson = parse_json(request_processors_async_s)\\n| mv-expand Processor = ParsedJson // Expanding the array\\n| extend processorName = tostring(Processor.name),\\n completed = tobool(Processor.details.completed),\\n duration = todouble(Processor.details.timestamp.duration)\\n| summarize countCompleted = sum(iif(completed == true, 1, 0)), \\n countNotCompleted = sum(iif(completed == false, 1, 0)), \\n averageDuration = round(avg(duration),2) by DynamicColumn, processorName\\n| order by DynamicColumn, processorName\\n\",\"size\":4,\"title\":\"Request Processors Async Execution\",\"noDataMessage\":\"The query returned no result\",\"timeContextFromParameter\":\"ingressStartTime\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"Request Processors Async Execution\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let columnName = '{columnFilter}'; // Use the workbook parameter\\nlet start_time = todatetime('{ingressStartTime:startISO}'); // Use the workbook parameter\\nlet end_time = todatetime('{ingressStartTime:endISO}'); // Use the workbook parameter\\nlet findIngressStartTimeStamp = (t:datetime, s:string) { // We don't trust the log analytics indexing\\n coalesce(t, todatetime(s))\\n};\\ngecholog_CL\\n| extend ingressStartTimeStamp = findIngressStartTimeStamp(column_ifexists('ingress_egress_timer_start_t', datetime(null)), ingress_egress_timer_start_s)\\n| where ingressStartTimeStamp >= start_time and ingressStartTimeStamp <= end_time\\n| extend DynamicColumn = coalesce(column_ifexists(columnName, \\\"\\\"), \\\"NaN\\\")\\n| project response_processors_async_s, DynamicColumn\\n| extend ParsedJson = parse_json(response_processors_async_s)\\n| mv-expand Processor = ParsedJson // Expanding the array\\n| extend processorName = tostring(Processor.name),\\n completed = tobool(Processor.details.completed),\\n duration = todouble(Processor.details.timestamp.duration)\\n| summarize countCompleted = sum(iif(completed == true, 1, 0)), \\n countNotCompleted = sum(iif(completed == false, 1, 0)), \\n averageDuration = round(avg(duration),2) by DynamicColumn, processorName\\n| order by DynamicColumn, processorName\\n\",\"size\":4,\"title\":\"Response Processors Async Execution\",\"timeContextFromParameter\":\"ingressStartTime\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"Response Processors Async Execution\"},{\"type\":1,\"content\":{\"json\":\"# Fields\",\"style\":\"info\"},\"name\":\"text - 17\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"gecholog_CL\\n| getschema\\n| extend Prefix = coalesce(\\n extract(\\\"^(\\\\\\\\w+?_\\\\\\\\w+?_\\\\\\\\w+?_)\\\", 0, ColumnName),\\n extract(\\\"^(\\\\\\\\w+?_\\\\\\\\w+?_)\\\", 0, ColumnName),\\n extract(\\\"^(\\\\\\\\w+?_)\\\", 0, ColumnName)\\n )\\n| summarize Columns = make_list(ColumnName) by Prefix\\n| order by Prefix asc \\n| project Prefix, ColumnNames = strcat_array(Columns, \\\", \\\")\\n\\n\\n\\n\",\"size\":3,\"title\":\"Gecholog - Log Analytics Schema\",\"timeContextFromParameter\":\"ingressStartTime\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"query - 2\"},{\"type\":1,\"content\":{\"json\":\"# Transaction Finder\",\"style\":\"info\"},\"name\":\"text - 15\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"parameters\":[{\"id\":\"8a6141d4-2614-4db2-8155-7451ab7c2f47\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"statusCode\",\"type\":2,\"isRequired\":true,\"query\":\"gecholog_CL\\n| distinct response_egress_status_code_d\",\"typeSettings\":{\"additionalResourceOptions\":[\"value::1\"],\"showDefault\":false},\"timeContext\":{\"durationMs\":86400000},\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"value\":\"200\"},{\"id\":\"aca428e9-0a73-4312-aae9-99454631a7a5\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"transactionIDRegex\",\"type\":1,\"timeContext\":{\"durationMs\":86400000},\"value\":\"\"},{\"id\":\"d8c9ca24-0b1a-4bda-a790-384dcefc5877\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"minDuration\",\"type\":1,\"timeContext\":{\"durationMs\":86400000},\"value\":\"\"},{\"id\":\"0dffa56c-2860-4f45-8b90-9fa932ea6f5c\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"maxDuration\",\"type\":1,\"timeContext\":{\"durationMs\":86400000},\"value\":\"\"},{\"id\":\"b41b51a5-1c1c-4123-94b3-e41f9d4464c5\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"minTokens\",\"type\":1,\"timeContext\":{\"durationMs\":86400000},\"value\":\"\"},{\"id\":\"c0087e66-fc43-44ba-bd7c-c5882b8382ec\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"maxTokens\",\"type\":1,\"timeContext\":{\"durationMs\":86400000},\"value\":\"\"}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"parameters - 21\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let columnName = '{columnFilter}'; // Use the workbook parameter\\nlet start_time = todatetime('{ingressStartTime:startISO}'); // Use the workbook parameter\\nlet end_time = todatetime('{ingressStartTime:endISO}'); // Use the workbook parameter\\nlet status_code = toint('{statusCode}');\\nlet findIngressStartTimeStamp = (t:datetime, s:string) { // We don't trust the log analytics indexing\\n coalesce(t, todatetime(s))\\n};\\nlet transaction_id_pattern = coalesce('{transactionIDRegex}', '.');\\nlet minDurationValue = toint(coalesce('{minDuration}', '0')); // Convert to integer and set default to 0 if null\\nlet duration_min = iif(minDurationValue > 0, minDurationValue, 0);\\nlet maxDurationValue = toint(coalesce('{maxDuration}', '0')); // Convert to integer and set default to 0 if null\\nlet duration_max = iif(maxDurationValue <> 0, maxDurationValue, 360000000);\\nlet minTokenValue = toint(coalesce('{minTokens}', '0')); // Convert to integer and set default to 0 if null\\nlet token_min = iif(minTokenValue > 0, minTokenValue, 0);\\nlet maxTokenValue = toint(coalesce('{maxTokens}', '0')); // Convert to integer and set default to 0 if null\\nlet token_max = iif(maxTokenValue <> 0, maxTokenValue, 360000000000000);\\ngecholog_CL\\n| extend ingressStartTimeStamp = findIngressStartTimeStamp(column_ifexists('ingress_egress_timer_start_t', datetime(null)), ingress_egress_timer_start_s)\\n| extend response_token_count_total_tokens = coalesce(column_ifexists('response_token_count_total_tokens_d', toreal(0)),toreal(0))\\n| where ingressStartTimeStamp >= start_time and ingressStartTimeStamp <= end_time\\n| extend DynamicColumn = coalesce(column_ifexists(columnName, \\\"\\\"), \\\"NaN\\\")\\n| where transaction_id_s matches regex transaction_id_pattern\\n| where ingress_egress_timer_duration_d >= duration_min\\n| where ingress_egress_timer_duration_d <= duration_max\\n| where response_token_count_total_tokens >= token_min\\n| where response_token_count_total_tokens <= token_max\\n| where status_code == response_egress_status_code_d\\n| project DynamicColumn, ingressStartTimeStamp, transaction_id_s, session_id_s, ingress_egress_timer_duration_d, response_token_count_total_tokens, response_egress_status_code_d\\n| order by ingressStartTimeStamp desc\\n\",\"size\":0,\"title\":\"Transaction Finder\",\"timeContextFromParameter\":\"ingressStartTime\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"Transaction Finder\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"parameters\":[{\"id\":\"1f78c634-7b32-42e9-ac01-5584410f30ca\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"transactionID\",\"type\":1,\"timeContext\":{\"durationMs\":86400000},\"value\":\"\"}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"parameters - 20\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let transaction_id = '{transactionID}';\\ngecholog_CL\\n| where transaction_id_s == transaction_id\\n| project clickOnThisToReviewContent = pack_all()\\n\",\"size\":4,\"title\":\"Open Transaction\",\"timeContextFromParameter\":\"ingressStartTime\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"Open Transaction\"}],\"isLocked\":false,\"fallbackResourceIds\":[\"/subscriptions/aa1fa7e2-6d38-5333-bf49-8025e5f723e9/resourcegroups/gecholog/providers/microsoft.operationalinsights/workspaces/gechologspace\"]}", "serializedDataString": "[replace(variables('rawSerializedDataStr'), '/subscriptions/aa1fa7e2-6d38-5333-bf49-8025e5f723e9/resourcegroups/gecholog/providers/microsoft.operationalinsights/workspaces/gechologspace', resourceId('Microsoft.OperationalInsights/workspaces', parameters('logSpaceName')))]" }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2022-09-01", "name": "[parameters('storageAccountName')]", "location": "[parameters('location')]", "sku": { "name": "Standard_LRS" }, "kind": "StorageV2", "properties": {} }, { "type": "Microsoft.Storage/storageAccounts/fileServices", "apiVersion": "2022-09-01", "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", "dependsOn": [ "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" ] }, { "type": "Microsoft.Storage/storageAccounts/fileServices/shares", "apiVersion": "2021-04-01", "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('confFileShareName'))]", "properties": {}, "dependsOn": [ "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), 'default')]" ] }, { "type": "Microsoft.Storage/storageAccounts/fileServices/shares", "apiVersion": "2021-04-01", "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('logFileShareName'))]", "properties": {}, "dependsOn": [ "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), 'default')]" ] }, { "type": "Microsoft.OperationalInsights/workspaces", "apiVersion": "2021-06-01", "name": "[parameters('logSpaceName')]", "location": "[parameters('location')]", "properties": { "sku": { "name": "[parameters('sku')]" }, "retentionInDays": 30 } }, { "type": "Microsoft.Insights/workbooks", "apiVersion": "2022-04-01", "name": "[parameters('workbookId')]", "location": "[parameters('location')]", "kind": "shared", "properties": { "displayName": "[variables('workbookDisplayName')]", "serializedData": "[variables('serializedDataString')]", "version": "1.0", "sourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logSpaceName'))]", "category": "[variables('workbookType')]" }, "dependsOn": [ "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logSpaceName'))]" ] }, { "type": "Microsoft.ContainerInstance/containerGroups", "apiVersion": "2021-09-01", "name": "[parameters('containerGroupName')]", "location": "[parameters('location')]", "properties": { "containers": [ { "name": "[parameters('containerGroupName')]", "properties": { "image": "[parameters('image')]", "ports": [ { "port": "[parameters('port')]", "protocol": "TCP" }, { "port": "[parameters('guiPort')]", "protocol": "TCP" }, { "port": 4222, "protocol": "TCP" } ], "resources": { "requests": { "cpu": "[parameters('cpuCores')]", "memoryInGB": "[parameters('memoryInGb')]" } }, "environmentVariables": [ { "name": "AISERVICE_API_BASE", "value": "[parameters('aiServiceApiBase')]" }, { "name": "NATS2LOG_LOGGER_SUBTOPIC", "value": "[parameters('nats2logLoggerSubTopic')]" }, { "name": "NATS2FILE_LOGGER_SUBTOPIC", "value": "[parameters('nats2fileLoggerSubTopic')]" }, { "name": "AZURE_LOG_ANALYTICS_WORKSPACE_ID", "value": "[reference(resourceId('Microsoft.OperationalInsights/workspaces', parameters('logSpaceName')), '2021-06-01').customerId]" }, { "name": "AZURE_LOG_ANALYTICS_SHARED_KEY", "secureValue": "[listKeys(resourceId('Microsoft.OperationalInsights/workspaces', parameters('logSpaceName')), '2021-06-01').primarySharedKey]" }, { "name": "AZURE_STORAGE_ACCESS_KEY", "secureValue": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2021-08-01').keys[0].value]" }, { "name": "GECHOLOG_API_KEY", "secureValue": "[parameters('gechologApiKey')]" }, { "name": "AISERVICE_API_KEY", "secureValue": "[parameters('aiServiceApiKey')]" }, { "name": "NATS_TOKEN", "secureValue": "[parameters('natsToken')]" }, { "name": "GUI_SECRET", "secureValue": "[parameters('guiSecret')]" } ], "volumeMounts": [ { "name": "conf", "mountPath": "/app/conf" }, { "name": "log", "mountPath": "/app/log" } ] } } ], "osType": "Linux", "restartPolicy": "[parameters('restartPolicy')]", "ipAddress": { "type": "Public", "dnsNameLabel": "[variables('dnsNameLabelUnique')]", "ports": [ { "port": "[parameters('port')]", "protocol": "TCP" }, { "port": "[parameters('guiPort')]", "protocol": "TCP" }, { "port": 4222, "protocol": "TCP" } ] }, "volumes": [ { "name": "conf", "azureFile": { "shareName": "[parameters('confFileShareName')]", "storageAccountName": "[parameters('storageAccountName')]", "storageAccountKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2021-08-01').keys[0].value]", "readOnly": false } }, { "name": "log", "azureFile": { "shareName": "[parameters('logFileShareName')]", "storageAccountName": "[parameters('storageAccountName')]", "storageAccountKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2021-08-01').keys[0].value]", "readOnly": false } } ] }, "dependsOn": [ "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logSpaceName'))]", "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" ] } ], "outputs": { "containerGroupFqdn": { "type": "string", "value": "[reference(resourceId('Microsoft.ContainerInstance/containerGroups', parameters('containerGroupName')), '2021-09-01').ipAddress.fqdn]" }, "containerIPv4Address": { "type": "string", "value": "[reference(resourceId('Microsoft.ContainerInstance/containerGroups', parameters('containerGroupName')), '2021-09-01').ipAddress.ip]" } } }