Skip to content

Creating new KQL functions via plugins

Neil MacMullen edited this page Aug 16, 2025 · 1 revision

Creating a Custom KQL Function Plugin

This tutorial demonstrates how to create a custom KQL (Kusto Query Language) function plugin for LokqlDx. When the plugin is loaded, you'll have access to a fizz function which you can use in queries to play the fizzbuzz game.


1. Setup

Create a new class-library project. Add package references to KustoLoco.PluginSupport, KustoLoco.Core and KustoLoco.SourceGeneration.Attributes.

Don't forget to add

    <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>

to your csproj to enable the source-generator to do its magic.

2. Define the Function Implementation

Create a class for your function and decorate it with the [KustoImplementation] attribute. Implement static methods for the function logic.

For FizzBuzz, we want a function that returns "fizz", "buzz", or "fizzbuzz" depending on the input value. To demonstrate that we can operate on different signatures, we'll also add a variant that operates on a string.

Some points of note:

  • Although it's not shown here, you can have multiple parameters in the implementation methods.
  • Note that all implementation methods must end with Impl.
  • The source-generator adds scaffolding around the implementation methods that ensures that they will only be called when the supplied parameters are not null so there's no need to deal with null-handling. It also adds caching and parallelisation.
  • In this particular example we've moved the core logic to an external class FizzBuzzCalculator. The reason for this is that the source-generator recreates the implementation methods in a new class so the call to FizzBuzz needs to be qualified. We could also move the FizzBuzz function back into the FizzFunction class and refer to it as FizzFunction.FizzBuzz but many refactoring tools will automatically remove the qualifier in this case and break the code.
using KustoLoco.SourceGeneration.Attributes;

namespace FizzBuzzPlugin;

[KustoImplementation(Keyword = "fizz")]
public partial class FizzFunction
{
    public static string LongImpl(long n)
    => FizzBuzzCalculator.FizzBuzz(n);

    public static string StringImpl(string text)
    {
        var n  =  (int.TryParse(text, out var parsed)
          ? parsed
          : text.Length;
        return FizzBuzzCalculator.FizzBuzz(n);
      
    }
}

public static class FizzBuzzCalculator
{
    public static FizzBuzz(int n)
    {
      var fizz = n % 3 == 0 ? "fizz" : string.Empty;
      var buzz = n % 5 == 0 ? "buzz" : string.Empty;
      return fizz + buzz;
    }
}

3. Create the Plugin Class

Implement the IKqlFunction interface to register your function with the engine. This allows the engine to discover and use your function.

using Kusto.Language.Symbols;
using KustoLoco.Core.Evaluation.BuiltIns;
using KustoLoco.PluginSupport;

namespace FizzBuzzPlugin;

public class FizzBuzzFunctionPlugin : IKqlFunction
{
    public string GetNameAndVersion() => "FizzBuzz v1";

    public void Register(Dictionary<FunctionSymbol, ScalarFunctionInfo> registration)
        => FizzFunction.Register(registration);
}

4. Deploying

The plugin should be built as a DLL. A single dll can contain multiple functions.

LokqlDx expects plugins to live in a folder-structure with each plugin in its own folder. The folder-name must be the same as the main dll in the plugin. For example:

C:\kusto\plugins
|---FizzBuzzPlugin
|       FizzBuzzPlugin.dll
|
|---ProcessesPlugin
        ProcessesPlugin.dll

Node that it's normally sufficient just to copy across the main dll; any kusto-related dlls can be ignored.

Set the Plugins Folder in the Application Preferences and restart the application. In the example above it would be set to c:\kusto\plugins


5. Using the Function in a Query

Once deployed, your function will be available in the query window. For example:

range n from 1 to 100 step 1 
| extend FizzBuzz = fizz(n)

6. Further reading

For more details, see the FizzBuzzPlugin sample in the repository.

Clone this wiki locally