/ ProjectPlugins / MetricsPlugin / PrometheusStarter.cs
PrometheusStarter.cs
 1  using Core;
 2  using KubernetesWorkflow;
 3  using KubernetesWorkflow.Types;
 4  using Logging;
 5  using System.Text;
 6  using Utils;
 7  
 8  namespace MetricsPlugin
 9  {
10      public class PrometheusStarter
11      {
12          private readonly PrometheusContainerRecipe recipe = new PrometheusContainerRecipe();
13          private readonly IPluginTools tools;
14  
15          public PrometheusStarter(IPluginTools tools)
16          {
17              this.tools = tools;
18          }
19  
20          public RunningPod CollectMetricsFor(Address[] targets, TimeSpan scrapeInterval)
21          {
22              if (!targets.Any()) throw new ArgumentException(nameof(targets) + " must not be empty.");
23  
24              Log($"Starting metrics server for {targets.Length} targets...");
25              var startupConfig = new StartupConfig();
26              startupConfig.Add(new PrometheusStartupConfig(GeneratePrometheusConfig(targets, scrapeInterval)));
27  
28              var workflow = tools.CreateWorkflow();
29              var runningContainers = workflow.Start(1, recipe, startupConfig).WaitForOnline();
30              if (runningContainers.Containers.Length != 1) throw new InvalidOperationException("Expected only 1 Prometheus container to be created.");
31  
32              Log("Metrics server started.");
33              return runningContainers;
34          }
35  
36          public MetricsAccess CreateAccessForTarget(RunningPod metricsPod, Address target)
37          {
38              var metricsQuery = new MetricsQuery(tools, metricsPod.Containers.Single());
39              return new MetricsAccess(metricsQuery, target);
40          }
41  
42          public string GetPrometheusId()
43          {
44              return recipe.Image;
45          }
46  
47          private void Log(string msg)
48          {
49              tools.GetLog().Log(msg);
50          }
51  
52          private string GeneratePrometheusConfig(Address[] targets, TimeSpan scrapeInterval)
53          {
54              var secs = Convert.ToInt32(scrapeInterval.TotalSeconds);
55              if (secs < 1) throw new Exception("ScrapeInterval can't be < 1s");
56              if (secs > 60) throw new Exception("ScrapeInterval can't be > 60s");
57  
58              var config = "";
59              config += "global:\n";
60              config += $"  scrape_interval: {secs}s\n";
61              config += $"  scrape_timeout: {secs}s\n";
62              config += "\n";
63              config += "scrape_configs:\n";
64              config += "  - job_name: services\n";
65              config += "    metrics_path: /metrics\n";
66              config += "    static_configs:\n";
67              config += "      - targets:\n";
68  
69              foreach (var target in targets)
70              {
71                  config += $"          - '{FormatTarget(target)}'\n";
72              }
73  
74              var bytes = Encoding.ASCII.GetBytes(config);
75              return Convert.ToBase64String(bytes);
76          }
77  
78          private string FormatTarget(Address target)
79          {
80              return ScrapeTargetHelper.FormatTarget(target);
81          }
82      }
83  
84      public static class ScrapeTargetHelper
85      {
86          public static string FormatTarget(Address target)
87          {
88              var host = target.Host.Replace("http://", "").Replace("https://", "");
89              return $"{host}:{target.Port}";
90          }
91      }
92  }