środa, 25 stycznia 2023

Integracja z API Splunk

Splunk to narzędzie ułatwiające pracę z danymi produkowanymi przez aplikacje (chodzi tu głównie o procesowanie logów aplikacji). Łatwo możemy agregować dane, tworzyć alerty, raporty, bogate prezentacje stanu naszego systemu. Więcej informacji i szczegółowy opis znajduje się na stronie producenta oprogramowania. 

Jak większość obecnych narzędzi, Splunk udostępnia API przy pomocy którego możemy rozszerzyć dostępne funkcjonalności. Ten post zaprezentuje w jaki sposób wywołać zapytanie w Splunku i następnie pobrać rezultaty dla niego.

Wyszukiwanie realizujemy w 3 krokach. Za pomocą instrukcji POST wysyłamy zapytanie do przetworzenia. Wynikiem jest Id (sid) naszego zapytania, który następnie możemy użyć aby sprawdzić stan wykonania zapytania, jak i później pobrać rezultat. 

Najłatwiej cały proces zobrazować w kodzie:

using System.Text;
using System.Xml.Linq;

using var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Authorization", $"Basic {EncodeAuthStringToBase64("splunk_user_name", "splunk_user_passowrd");

var queryResults = await GetQueryResultAsJson("search index=myindex earliest=-1m | stats count by host", httpClient);

Console.WriteLine(queryResults);


static string EncodeAuthStringToBase64(string userName, string password)
{
    var authenticationString = $"{userName}:{password}";
    return Convert.ToBase64String(Encoding.UTF8.GetBytes(authenticationString));
}

static async Task<string> GetQueryResultAsJson(string splunkQuery, HttpClient httpClient)
{
    const string splunkBaseAddress = "https://splunk_base_address:8089";
    var createSearchJobResult = await httpClient.PostAsync("{splunkBaseAddress}/services/search/jobs/", new FormUrlEncodedContent(new List<KeyValuePair<string, string>>
    {
        new("search", splunkQuery)
    }));

    var readAsStringAsync = await createSearchJobResult.Content.ReadAsStringAsync();
    var xDocument = XDocument.Parse(readAsStringAsync);
    var querySid = xDocument.Root.Element("sid").Value;

    bool isQueryDone;
    do
    {
        await Task.Delay(100);
        var statusOfQuery =
            await httpClient.GetStringAsync(
                $"{splunkBaseAddress}/services/search/jobs/{querySid}");
        isQueryDone = statusOfQuery.Contains("<s:key name=\"dispatchState\">DONE</s:key>");
    } while (!isQueryDone);

    var queryResults =
        await httpClient.GetStringAsync(
            $"{splunkBaseAddress}/services/search/v2/jobs/{querySid}/results/?output_mode=json");

    return queryResults;
}


Kod nie jest skomplikowany, może jednak klika słów wyjaśnienia rozwieje wątpliwości:

1. Pierwszym krokiem jest stworzenie klienta za pomocą którego będziemy się komunikowali ze Splunkiem (zapytanie POST i GET)

2. Użyjemy Basic Auth

3. Za pomocą POSTa wysyłamy zapytanie do przetworzenia przez Splunk na adres /services/search/jobs/.

4. W odpowiedzi na zapytanie otrzymujemy unikalny SID naszego zapytania, który użyjemy do sprawdzenia stanu wykonania zapytania jak i pobrania rezultatów po jego ukończeniu. 

5. Cyklicznie odpytujemy Splunk o status naszego zapytania. Dla przykładu rozważamy optymistyczny scenariusz, że zapytanie na pewno się powiedzie. W kodzie produkcyjnym powinny być obsłużone także inne możliwe stany (QUEUED,PARSING,RUNNING,FINALIZING,DONE,PAUSE,INTERNAL_CANCEL,USER_CANCEL,BAD_INPUT_CANCEL,QUIT,FAILED)

6. Po pewnym czasie zapytanie zostanie prztworzone i możemy pobrać jego rezultat za pomocą sid z adresu /services/search/v2/jobs/{querySid}/results/?output_mode=json.

Na tym momencie możemy już dowolnie obrobić rezultat (który notabene może być także innym typem np. atom | csv | json | json_cols | json_rows | raw | xml).

Brak komentarzy:

Prześlij komentarz