Migrating from Splunk SDK for C# v1.0.x

The Splunk SDK for C# version 2.x is a rewrite of the Splunk SDK for C# and introduces completely new APIs.

Important: Applications built with Splunk SDK for C# version 1.0.x will not recompile using Splunk SDK for C# version 2.x.

Splunk SDK for C# version 2.x includes a subset of the capability in version 1.0.x of the SDK, and focuses on the most common scenarios. The major focus areas are search, search jobs, configuration, and modular inputs. For more detailed information about supported functionality, see What you can do with the Splunk SDK for C#.

Among the differences between the Splunk SDK for C# versions 2.x and 1.0.x are the following:

  • Splunk SDK for C# v1.0.x is based on the Splunk SDK for Java, and features APIs that are written according to Java API naming conventions. Version 2.x of the Splunk SDK for C# has brand-new APIs with names and signatures that meet C# developer community expectations.
  • Splunk SDK for C# v2.x is asynchronous, returns a task, and supports new async/await features; while version 1.0.x of the Splunk SDK for C# is synchronous.
  • Splunk SDK for C# v2.x supports the async keyword, which requires, at minimum, the .NET Framework 4.0.
  • All Splunk SDK for C# v2.x APIs follow .NET guidelines and abide by FxCop and StyleCop rules.
  • The Splunk API client in Splunk SDK for C# v2.x is a Portable Class Library (PCL), and supports cross-platform development. (For more information about supported platforms, see Check prerequisites.)

There are some important differences between the two versions' APIs and how you complete some common tasks:

  • The Service.Connect method is no longer available. To create a new instance of the Service class, use one of its constructors. See the following comparison of code written with the two SDK versions for an example. This code retrieves a list of all Splunk Enterprise apps available to the current user, and prints them to the console. For the Splunk SDK for C# v2.x example, notice the use of the await operator and the new asynchronous methods.

    Splunk SDK for C# 1.0.x

    var service = Service.Connect(new Dictionary<string, object>
                {
                    {"hostname", "localhost"},
                    {"port", 8089},
                    {"scheme", "https"},
                    {"username", "admin"},
                    {"password", "changeme"}
                });
                 
    foreach (var app in service.GetApplications().Values)
    {
        Console.WriteLine(string.Format("{0}: {1}",
            app.Name, app.Description));
    }

    Splunk SDK for C# 2.x

    using (var service = new Service(
        Scheme.Https, "localhost",
        8089,
        new Namespace(user: "nobody", app: "search")))
    {
        await service.LogOnAsync("admin", "changeme");
     
        Console.WriteLine("List of Apps:");
        await service.Applications.GetAllAsync();
    
        foreach (var app in service.Applications)
        {
            Console.WriteLine(app.Name);
            // Write a seperator between the name and the description of an app.
            Console.WriteLine(Enumerable.Repeat<char>('-', app.Name.Length).ToArray());
            Console.WriteLine(app.Description);
        }
    }
  • Create and run search reports (also known as saved searches) using asynchronous methods. Instead of using the Create(), Get(), and Delete() methods, use the asynchronous methods CreateAsync(...), GetOrNullAsync(), and RemoveAsync(). For example, take a look at the following comparative example, which illustrates how to create and dispatch a search report (saved search) using both versions of the SDK:

    Splunk SDK for C# 1.0.x

    var service = Service.Connect(new Dictionary<string, object>
                {
                    {"hostname", "localhost"},
                    {"port", 8089},
                    {"scheme", "https"},
                    {"username", "admin"},
                    {"password", "changeme"}
                });
     
    SavedSearch savedSearch = service.GetSavedSearches().Create(
        "example_search", "search index=_internal | head 10");
    Job dispatchedJob = savedSearch.Dispatch();
     
    while (!dispatchedJob.IsDone)
    {
        Thread.Sleep(150);
    }
     
    using (var stream = dispatchedJob.Results())
    using (var rr = new ResultsReaderXml(stream))
    {
        foreach (var @event in rr)
        {
            System.Console.WriteLine("EVENT:");
            foreach (string key in @event.Keys)
            {
                System.Console.WriteLine("   " + key + " -> " + @event[key]);
            }
        }
    }
     
    savedSearch.Remove();

    Splunk SDK for C# 2.x

    using (var service = new Service(
        Scheme.Https, "localhost",
        8089,
        new Namespace(user: "nobody", app: "search")))
    {
        await service.LogOnAsync("admin", "changeme");
     
        string savedSearchName = "example_search";
        string savedSearchQuery = "search index=_internal | head 10";
     
        // Delete the saved search if it exists before we start.
        SavedSearch savedSearch = await service.SavedSearches.GetOrNullAsync(savedSearchName);
    
        if (savedSearch != null)
        {
            await savedSearch.RemoveAsync();
        }
    
        savedSearch = await service.SavedSearches.CreateAsync(savedSearchName, savedSearchQuery);
        Job savedSearchJob = await savedSearch.DispatchAsync();
    
        using (SearchResultStream stream = await savedSearchJob.GetSearchResultsAsync())
        {
            foreach (SearchResult result in stream)
            {
                Console.WriteLine(result);
            }
        }
    
        await savedSearch.RemoveAsync();
    
  • To run and get results from actions that can only return results when completed—such as a normal search—you can now use asynchronous methods such as Job.GetSearchResultsAsync to avoid having to sleep the thread. For an example, see the following comparison:

    Splunk SDK for C# 1.0.x

    var service = Service.Connect(new Dictionary<string, object>
                {
                    {"hostname", "localhost"},
                    {"port", 8089},
                    {"scheme", "https"},
                    {"username", "admin"},
                    {"password", "changeme"}
                });
        var job = service.GetJobs().Create(
            "search index=_internal | head 10");
     
        while (!job.IsDone) 
        {
            Thread.Sleep(150);
        }
     
        using (var stream = job.Results())
        {
            using (var rr = new ResultsReaderXml(stream))
            {
                foreach (var @event in rr)
                {
                    System.Console.WriteLine("EVENT:");
                    foreach (string key in @event.Keys)
                    {
                        System.Console.WriteLine("   " + key + 
                           " -> " + @event[key]);
                    }
                }
            }
        }
    }

    Splunk SDK for C# 2.x

    using (var service = new Service(
        Scheme.Https, "localhost",
        8089,
        new Namespace(user: "nobody", app: "search")))
    {
        await service.LogOnAsync("admin", "changeme");
     
        Job job = await service.Jobs.CreateAsync("search index=_internal | head 10");
        SearchResultStream stream;
    
        using (stream = await job.GetSearchResultsAsync())
        {
            try
            {
                foreach (SearchResult result in stream)
                {
                    Console.WriteLine(string.Format("{0:D8}: {1}", stream.ReadCount, result));
                }
                        
                Console.WriteLine("End of search results");
            }
            catch (Exception e)
            {
            Console.WriteLine(string.Format("SearchResults error: {0}", e.Message));
            }
        }
    }
  • To run a search in real-time and print preview results at regular intervals, you can now use the Task.Delay method to delay the thread asynchronously instead of sleeping it. For example:

    Splunk SDK for C# 1.0.x

    var service = Service.Connect(new Dictionary<string, object>
                {
                    {"hostname", "localhost"},
                    {"port", 8089},
                    {"scheme", "https"},
                    {"username", "admin"},
                    {"password", "changeme"}
                });
     
    var queryArgs = new JobArgs 
    { 
        SearchMode = JobArgs.SearchModeEnum.Realtime,
        EarliestTime = "rt-5m", 
        LatestTime = "rt",
    };
    var job = service.GetJobs().Create(
        "search index=_internal | stats count by method", 
        queryArgs);
     
    for (var i = 0; i < 5; i++)
    {
        System.Console.WriteLine();
        System.Console.WriteLine();
        System.Console.WriteLine("Snapshot " + i + ":"); 
                     
        using (var stream = job.ResultsPreview(outputArgs))
        using(var rr = new ResultsReaderXml(stream))
        {
            foreach (var @event in rr)
            {
                System.Console.WriteLine("EVENT:");
                foreach (string key in @event.Keys)
                {
                    System.Console.WriteLine(
                        "   " + key + " -> " + @event[key]);
                }
            }
        }
         
        Thread.Sleep(500);
    }
    job.Cancel();

    Splunk SDK for C# 2.x

    using (var service = new Service(
        Scheme.Https, "localhost",
        8089,
        new Namespace(user: "nobody", app: "search")))
    {
        await service.LogOnAsync("admin", "changeme");
     
        Console.WriteLine("Press return to cancel.");
    
        string searchQuery = "search index=_internal | stats count by method";
    
        Job realtimeJob = await service.Jobs.CreateAsync(searchQuery, args: new JobArgs
        {
            SearchMode = SearchMode.RealTime,
            EarliestTime = "rt-1h",
            LatestTime = "rt",
        });
    
        var tokenSource = new CancellationTokenSource();
    
        Task.Run(async () =>
        {
            Console.ReadLine();
    
            await realtimeJob.CancelAsync();
            tokenSource.Cancel();
        });
    
        while (!tokenSource.IsCancellationRequested)
        {
            using (SearchResultStream stream = await realtimeJob.GetSearchPreviewAsync())
            {
                Console.WriteLine("fieldnames: " + string.Join(";", stream.FieldNames));
                Console.WriteLine("fieldname count: " + stream.FieldNames.Count);
                Console.WriteLine("final result: " + stream.IsFinal);
    
                foreach (SearchResult result in stream)
                {
                    Console.WriteLine(result);
                }
    
                Console.WriteLine("");
                await Task.Delay(2000, tokenSource.Token);
            }
        }