Created
July 28, 2021 19:59
-
-
Save nirvincricut/fc222553e1ac6ed4ad00178c104b41c1 to your computer and use it in GitHub Desktop.
Search Grafana dashboards for keyword (.NET Core 3.1)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
namespace GrafanaQuery | |
{ | |
public class DashboardContent | |
{ | |
public List<PanelInfo> Panels { get; set; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Newtonsoft.Json; //include this NuGet package (12.0.3) | |
namespace GrafanaQuery | |
{ | |
public class DashboardInfo | |
{ | |
[JsonProperty] | |
public int Id { get; set; } | |
[JsonIgnore] | |
public int CurrentVersionNumber { get; set; } | |
[JsonProperty] | |
public string Title { get; set; } | |
[JsonIgnore] | |
public string TopEditorUserName { get; set; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Newtonsoft.Json; | |
namespace GrafanaQuery | |
{ | |
public class PanelInfo | |
{ | |
[JsonProperty("datasource")] | |
public string DataSourceName { get; set; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics.CodeAnalysis; | |
using System.IO; | |
using System.Linq; | |
using System.Security.Principal; //NuGet package System.Security.Principal.Windows 5.0.0 | |
using System.Threading; | |
using System.Threading.Tasks; | |
using Flurl.Http; //include this NuGet package (3.0.1) | |
namespace GrafanaQuery | |
{ | |
internal static class Program | |
{ | |
private static string _password; | |
private static string LoginName => WindowsIdentity.GetCurrent().Name.Substring(11); | |
private static readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); | |
private static StreamWriter _fileWriter; | |
private static string GrafanaHost => Environment.GetCommandLineArgs().Skip(1).First(); | |
private static string SearchTerm => Environment.GetCommandLineArgs().Skip(1).ToList()[1]; | |
private static async Task Main() | |
{ | |
Console.CancelKeyPress += OnCancelKeyPress; | |
try | |
{ | |
LoadPassword(); | |
string fileName = $"{Path.GetTempFileName()}.txt"; | |
_fileWriter = new StreamWriter(File.Open(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read)); | |
await RunQuery(); | |
Console.WriteLine($"Results file: {fileName}"); | |
} | |
catch (TaskCanceledException) | |
{ | |
Console.WriteLine("*** Stopped by user"); | |
Environment.ExitCode = 0; | |
} | |
catch (Exception exception) | |
{ | |
Console.WriteLine(exception); | |
Environment.ExitCode = -1; | |
} | |
finally | |
{ | |
await _fileWriter.DisposeAsync(); | |
_fileWriter = null; | |
} | |
} | |
private static void OnCancelKeyPress(object sender, ConsoleCancelEventArgs eventArgs) | |
{ | |
eventArgs.Cancel = true; | |
_cancellationTokenSource.Cancel(); | |
} | |
private static void LoadPassword() | |
{ | |
Console.Write($"Enter password for {LoginName}: "); | |
_password = ReadPassword(); | |
Console.WriteLine(); | |
} | |
private static async Task RunQuery() | |
{ | |
List<DashboardInfo> dashboards = await GetAllDashboards(); | |
for (int i = 0; i < dashboards.Count; i++) | |
{ | |
DashboardInfo dashboardInfo = dashboards[i]; | |
Console.WriteLine($"Querying {i + 1} of {dashboards.Count}..."); | |
List<VersionInfo> dashboardVersions = await GetDashboardVersions(dashboardInfo.Id); | |
dashboardInfo.TopEditorUserName = GetTopEditorUserNameFrom(dashboardVersions); | |
dashboardInfo.CurrentVersionNumber = dashboardVersions.OrderByDescending(x => x.EditDate).First().VersionNumber; | |
await PrintDataSourceInfo(dashboardInfo); | |
} | |
} | |
//https://stackoverflow.com/a/3404522/1687106 | |
private static string ReadPassword() | |
{ | |
var pass = string.Empty; | |
ConsoleKey key; | |
do | |
{ | |
ConsoleKeyInfo keyInfo = Console.ReadKey(intercept: true); | |
key = keyInfo.Key; | |
if (key == ConsoleKey.Backspace && pass.Length > 0) | |
{ | |
Console.Write("\b \b"); | |
pass = pass[..^1]; | |
} | |
else if (!char.IsControl(keyInfo.KeyChar)) | |
{ | |
Console.Write("*"); | |
pass += keyInfo.KeyChar; | |
} | |
} while (key != ConsoleKey.Enter); | |
return pass; | |
} | |
private static async Task<List<DashboardInfo>> GetAllDashboards() | |
{ | |
return await GetGrafanaObject<List<DashboardInfo>>($"{GrafanaHost}/api/search?type=dash-db"); | |
} | |
private static async Task<List<VersionInfo>> GetDashboardVersions(int dashboardId) | |
{ | |
return await GetGrafanaObject<List<VersionInfo>>($"{GrafanaHost}/api/dashboards/id/{dashboardId}/versions"); | |
} | |
private static string GetTopEditorUserNameFrom(List<VersionInfo> dashboardVersions) | |
{ | |
return | |
dashboardVersions | |
.GroupBy(x => x.UserName) | |
.Select(editStats => new | |
{ | |
EditorUserName = editStats.Key, | |
TotalEditCount = editStats.Count() | |
}) | |
.OrderByDescending(x => x.TotalEditCount) | |
.FirstOrDefault()? | |
.EditorUserName; | |
} | |
[SuppressMessage("ReSharper", "StringLiteralTypo")] | |
private static async Task PrintDataSourceInfo(DashboardInfo dashboardInfo) | |
{ | |
List<string> dataSourceNames = await GetDataSourceNames(dashboardInfo.Id, dashboardInfo.CurrentVersionNumber); | |
if (dataSourceNames.Exists(d => d.Equals(SearchTerm, StringComparison.InvariantCultureIgnoreCase))) | |
{ | |
await PrintLine($"\t{dashboardInfo.Title} (by {dashboardInfo.TopEditorUserName})"); | |
} | |
} | |
[SuppressMessage("ReSharper", "TooManyDeclarations")] | |
private static async Task<List<string>> GetDataSourceNames(int dashboardId, int versionNumber) | |
{ | |
List<PanelInfo> panels = await GetDashboardPanels(dashboardId, versionNumber); | |
return panels != null | |
? panels | |
.Select(panelInfo => panelInfo.DataSourceName?.Trim()) | |
.Where(dataSourceName => !string.IsNullOrWhiteSpace(dataSourceName)) | |
.Distinct() | |
.OrderBy(d => d) | |
.ToList() | |
: new List<string>(); | |
} | |
private static async Task<List<PanelInfo>> GetDashboardPanels(int dashboardId, int versionNumber) | |
{ | |
VersionInfo dashboardContent = await GetDashboardContent(dashboardId, versionNumber); | |
return dashboardContent?.Data?.Panels; | |
} | |
private static async Task<VersionInfo> GetDashboardContent(int dashboardId, int versionNumber) | |
{ | |
return await GetGrafanaObject<VersionInfo>($"{GrafanaHost}/api/dashboards/id/{dashboardId}/versions/{versionNumber}"); | |
} | |
private static async Task<T> GetGrafanaObject<T>(string url) | |
{ | |
return await url | |
.WithBasicAuth(LoginName, _password) | |
.GetJsonAsync<T>(_cancellationTokenSource.Token); | |
} | |
private static async Task PrintLine(string message) | |
{ | |
Console.WriteLine(message); | |
await _fileWriter.WriteLineAsync(message.ToCharArray(), _cancellationTokenSource.Token); | |
await _fileWriter.FlushAsync(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Newtonsoft.Json; | |
namespace GrafanaQuery | |
{ | |
public class VersionInfo | |
{ | |
[JsonProperty("id")] | |
public int VersionId { get; set; } | |
[JsonProperty("version")] | |
public int VersionNumber { get; set; } | |
[JsonProperty("Created")] | |
public DateTime EditDate { get; set; } | |
[JsonProperty("createdBy")] | |
public string UserName { get; set; } | |
public DashboardContent Data { get; set; } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment