How to Persist Column Selections in Azure Log Analytics KQL Queries


2 views

Many developers working with Azure Log Analytics encounter an interesting UX behavior when selecting columns through the portal interface. While you can manually specify columns using the project operator in Kusto Query Language (KQL):

AzureDiagnostics
| project TimeGenerated, httpMethod_s, statusCode_s

The visual column selector (shown in the interface screenshot) doesn't persist these selections in the actual query text. This creates confusion when:

  • Saving queries for future use
  • Sharing queries with team members
  • Version controlling your KQL scripts

The portal's column picker is actually a client-side visualization filter that operates independently from the query syntax. It's designed for quick exploration rather than query authoring.

Here's what's happening behind the scenes when you use the interface:

// What you see in the query editor
AzureDiagnostics
| where TimeGenerated > ago(1h)

// What actually gets sent to the backend
AzureDiagnostics
| where TimeGenerated > ago(1h)
| project-away * // Client removes unwanted columns after results return

For production-grade queries, you should always explicitly specify columns using KQL operators. Here are the recommended approaches:

Basic Column Projection

AzureDiagnostics
| project TimeGenerated, Resource, Category, OperationName, ResultSignature

Dynamic Column Selection

For more complex scenarios, you can use patterns like:

let selectedColumns = dynamic(["TimeGenerated", "httpMethod_s", "duration_d"]);
AzureDiagnostics
| project pack_all() // Preserve all fields as a property bag
| extend {selectedColumns}

If you really want to bridge the UI behavior with your query, you can use this workaround:

  1. Run your base query
  2. Select columns in the results grid
  3. Click "Export" > "Export to clipboard with headers"
  4. Paste into a text editor to see the exact column names
  5. Update your query with project using those names

For team environments, always:

  • Commit complete queries with explicit project statements
  • Document column purposes in comments
  • Use consistent column naming across related queries
// Good practice example with documentation
AzureDiagnostics
// Core tracking fields
| project Timestamp=TimeGenerated, 
          HTTPMethod=httpMethod_s,
          Status=statusCode_s,
          DurationMs=duration_d
// Filter to successful requests          
| where Status == 200

When working with Azure Log Analytics, many developers encounter an interesting quirk in the Kusto Query Language (KQL) interface. While you can select columns visually using the UI's column picker, these selections don't automatically reflect in the query text.

The issue manifests in two ways:

  1. The query editor doesn't update when columns are selected through the UI
  2. Column selections aren't preserved when saving queries

This becomes particularly frustrating when trying to:

  • Share queries with team members
  • Version control your queries
  • Create reproducible queries for automation

To ensure your column selections persist, you must explicitly include them in your KQL using the project operator. Here's the correct approach:

AzureDiagnostics
| where TimeGenerated > ago(1d)
| project 
    TimeGenerated,
    httpMethod_s,
    requestUri_s,
    statusCode_d,
    clientIP_s,
    duration_d

While the visual column picker seems convenient, manually specifying columns offers several advantages:

  • Query intent clarity: Makes your query's purpose more obvious
  • Performance optimization: Reduces data processing by limiting columns early
  • Reproducibility: Ensures consistent results across executions

For more complex scenarios, consider these patterns:

Dynamic column selection:

let selectedColumns = dynamic(["TimeGenerated", "httpMethod_s", "statusCode_d"]);
AzureDiagnostics
| project pack_array(selectedColumns)

Column patterns:

AzureDiagnostics
| project column_ifexists("http*", ""), TimeGenerated

Renaming columns during projection:

AzureDiagnostics
| project 
    Timestamp = TimeGenerated,
    Method = httpMethod_s,
    URI = requestUri_s

When creating queries for production use:

  • Always explicitly list columns in project
  • Consider column order for readability
  • Use column aliases for clearer field names
  • Document your column selections in query comments