-
Notifications
You must be signed in to change notification settings - Fork 23
Using the query engine
Libraries are available on Nuget - search for KustoLoco
Using the query engine from within an application is generally straightforward and follows a consistent pattern.
- Create a
KustoQueryContextthat will hold the set of tables that describe your data - Add tables to the context
- Issue a KQL query
- Do something with the result of the query.
- Goto 3
Here's an example of reading a list of processes, running a query and rendering the result into a DataTable for presentation in a GridView....
var context = new KustoQueryContext();
context.WrapDataIntoTable("processes", processes);
var result = await context.RunQuery("process | where Name contains 'code');
var dataTable = result.ToDataTable();Tables can easily be generated from:
- C# records or POCOs
- DataTables and DataSets
- A number of standard file formats including
- CSV
- Parquet
- JSON
- Text
- code-based injection via the TableBuilder class
Data can be loaded from a variety of table formats using instances of the ITableSerializer interface. For example
var settings = new KustoSettings();
settings.Set("csv.trimcells","off"); //allow leading/trailing whitespace in cells
var reporter = new ConsoleProgressReporter(); //send progress and errors to Console.WriteLine
var csvResult = await CsvSerializer.Default.LoadTable(@"c:\kusto\data.csv", "csvdata", reporter,settings);
if (csvResult.Error.IsNotBlank()) {... perform some error handling ...}
var parquetResult = await new ParquetSerializer().LoadTable(@"c:\kusto\data.parquet", "parquetdata", reporter,settings);
if (parquetResult.Error.IsNotBlank()) {... perform some error handling ...}
var context = new KustoQueryContext()
.AddTable(csvResult.Table)
.AddTable(parquetResult.Table);If the data being passed in will be "owned" by the the context, it is safe to use the WrapDataIntoTable method but if you just want to take a snapshot of data which may be mutated outside of the context, the CopyDataIntoTable method is safer.
See this page for a fuller discussion.
public readonly record struct MyThing(string Name,int Size);
public class MyMutableThing(string Name,int Size);
IReadOnlyCollection<MyThing> myThings = ... create a set of MyThings ...
IReadOnlyCollection<MyMutableThing> myMutableThings = ... create a set of MyMutableThings ...
var context = new KustoQueryContext()
.WrapDataIntoTable("things",myThings)
.CopyDataIntoTable("things2,myMutableThings);var context = new KustoQueryContext()
.AddTableFromDataTable(myDataTable);
var context = new KustoQueryContext()
.AddTablesFromDataSet(myDataSet);Kusto can only work with the CLR types bool,int,long,decimal,float,double,string,DateTime,TimeSpan,Guid,JsonNode. If you wish to import DTOs that contain custom types, you can use the KustoTypeConverter class...
// assume dto contains a property of type Identifier which we wish to process as a string,
// and a property of type Configuration which we want to treat as a dynamic (JsonNode)
var idConverter = new KustoTypeConverter<Identifier,string>(id=>id.ToString());
var configConverter = new KustoTypeConverter<Configuration,JsonNode>(cfg=>JsonSerializer.Serialize(cfg));
var context = new KustoQueryContext()
.WrapDataIntoTable<MyDto>("data",dtos,[idConverter,configConverter]);KustoTypeConverter can also acccept a Func<string,TSource,TTarget> in case you need to process properties differently according to their names:
var myConverter = new KustoTypeConverter<Configuration,string>((name,value)=>$"{name} is {value}");Note that the default behaviour for unrecognised types with no registered converter is to convert them to strings using ToString
Query results are encapsulated by a KustoQueryResult object. If the query fails (for example because of invalid syntax), the Error property will be non-blank and the results table will be empty. It is therefore always safe to render a KustoQueryResult since in case of an error an empty table or chart should be produced.
The core library natively supports rendering to a System.Data.DataTable. This can be used to populate a WPF DataGrid...
var result = await context.RunQuery(....);
var dataTable = result.ToDataTable(maxRowsToDisplay);
myDataGrid.ItemsSource = dataTable.DefaultView;var result = await context.RunQuery(....);
//set the rendering options
var settings = new KustoSettingsProvider();
settings.Set("scottplot.palette","penumbra");
//render to sixel
var sixel =ScottPlotKustoResultRenderer.RenderToSixelWithPad(result, settings, 5);
Console.Writeline(sixel);
//render to image
var format = ImageFormat.Png;
var imageBytes = ScottPlotKustoResultRenderer.RenderToImage(result, format, 800, 600, settings);
//render to Plot control
WpfPlot1.Reset();
var plot = WpfPlot1.Plot;
plot.Clear();
ScottPlotKustoResultRenderer.RenderToPlot(WpfPlot1.Plot,result,settings);
WpfPlot1.Refresh();The KustoLoco.Rendering library can be used to render results to html and display them in a WPF WebView control.
var result = await context.RunQuery(....);
var html = KustoResultRenderer.RenderToHtml(result);
webview.NavigateToString(html);The default behaviour is to:
- render the error message if the query failed
- render the result as an html table if the query was successful but does not include a
renderoperator - render the result as a Vega chart if the
renderoperator was used
For generalised text output, code similar to the following can be used to process the rows and cells of a result...
//display the results as a pretty Spectre.Console table
var table = new Table();
// Add columns with header names
foreach (var column in queryResult.ColumnDefinitions())
table.AddColumn(column.Name);
// Add rows. Note that cells could contain nulls in the general case
foreach (var row in queryResult.EnumerateRows())
{
var rowCells = row.Select(CellToString).ToArray();
table.AddRow(rowCells);
}
AnsiConsole.Write(table);
//local method for string conversion
string CellToString(object? cell) => cell?.ToString() ?? "<null>";One of the challenges of turning a query result back into POCOs is that the KQL syntax allows the "shape" of a result to be quite different to the input. For example, project and extend operators can be used to change the names and number of columns in the output data.
However, if you know the form of the query output the ToRecords method can be used..
public record MyExpectedType(string Type,int Count);
var result = await context.RunQuery(....);
var records = result.ToRecords<MyExpectedType>();Sometimes you want to send the result of a query across the wire. For example you might be serving query results from an API. A KustoQueryResult can be turned into a serializable from using a KustoResultSerializer which marshals the data into a string for transfer. The recommended serializer is ParquetResultSerializer.Default which turns the result data into a Parquet stream...
// Server code - turn a KustoQueryResult into a POCO which can be serialized to JSON
KustoQueryResult result = await context.RunQuery(query);
KustoResultDto dto = await ParquetResultSerializer.Default.Serialize(result);
string json = JsonSerializer.Serialize(dto);
// client code - get back to a KustoQueryResult
string json = await client.ReadStringAsync(....) ;
KustoResultDto dto = JsonSerializer.Deserialize<KustoResultDto>(text)
KustoQueryResult result = ParquetResultSerializer.Default.Deserialize(dto);Note that if the query contained a render operator, the transferred KustoQueryResult will contain the necessary VisualisationState required to perform a client-side render.
It's possible to extend the available set of KQL functions in the core engine as well as the set of commands provided by LokqlDx. See:
- https://github.com/NeilMacMullen/kusto-loco/wiki/Adding-custom-functions
- https://github.com/NeilMacMullen/kusto-loco/wiki/Creating-new-KQL-functions-via-plugins
- https://github.com/NeilMacMullen/kusto-loco/wiki/Creating-new-LokqlDx-commands-via-plugins
See the samples page for a list of working code-examples.
If you're using Kusto-Loco in a project, I'd love to hear about it. Post in the Showcase discussion forum.
#Home
Core Engine
Lokqldx (UI data explorer)
- Introduction
- Tutorials
- Running queries and commands
- Autocompletion
- Generating powerpoint reports
- Accessing ApplicationInsights data
Powershell
Other
Articles