diff --git a/generic jobs/Common/BaseDefault.cs b/generic jobs/Common/BaseDefault.cs index 00a6c6c4..e2af2621 100644 --- a/generic jobs/Common/BaseDefault.cs +++ b/generic jobs/Common/BaseDefault.cs @@ -30,6 +30,5 @@ protected BaseDefault(IConfigurationSection section, BaseDefault baseDefault) : public bool Veto { get; set; } public string? VetoReason { get; set; } - public CheckStatus CheckStatus { get; set; } } \ No newline at end of file diff --git a/generic jobs/FolderCheck/Folder.cs b/generic jobs/FolderCheck/Folder.cs index c710eb9c..cff24728 100644 --- a/generic jobs/FolderCheck/Folder.cs +++ b/generic jobs/FolderCheck/Folder.cs @@ -61,6 +61,8 @@ public Folder(IConfigurationSection section, Defaults defaults) : base(section, public string? CreatedAge { get; private set; } public string? ModifiedAge { get; private set; } + public FolderResult Result { get; } = new(); + //// --------------------------------------- //// public long? TotalSizeNumber { get; } diff --git a/generic jobs/FolderCheck/FolderResult.cs b/generic jobs/FolderCheck/FolderResult.cs new file mode 100644 index 00000000..c44c7b04 --- /dev/null +++ b/generic jobs/FolderCheck/FolderResult.cs @@ -0,0 +1,10 @@ +namespace FolderCheck; + +internal class FolderResult +{ + public long TotalSize { get; set; } + public long FileSize { get; set; } + public int FileCount { get; set; } + public DateTime? CreatedAge { get; set; } + public DateTime? ModifiedAge { get; set; } +} \ No newline at end of file diff --git a/generic jobs/FolderCheck/Job.cs b/generic jobs/FolderCheck/Job.cs index daa9112d..e391851c 100644 --- a/generic jobs/FolderCheck/Job.cs +++ b/generic jobs/FolderCheck/Job.cs @@ -3,8 +3,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Planar.Job; -using System.Net; -using YamlDotNet.Core.Tokens; namespace FolderCheck; @@ -154,9 +152,12 @@ private void InvokeFolderInner(Folder folder) var files = GetFiles(path, folder); var filesCount = files.Count(); + folder.Result.FileCount = filesCount; + if (folder.TotalSizeNumber != null && filesCount > 0) { var size = files.Sum(f => f.Length); + folder.Result.TotalSize = size; Logger.LogInformation("folder '{Path}' size is {Size:N0} byte(s)", path, size); if (size > folder.TotalSizeNumber) { @@ -167,6 +168,7 @@ private void InvokeFolderInner(Folder folder) if (folder.FileSizeNumber != null && filesCount > 0) { var max = files.Max(f => f.Length); + folder.Result.FileSize = max; Logger.LogInformation("folder '{Path}' max file size is {Size:N0} byte(s)", path, max); if (max > folder.FileSizeNumber) { @@ -186,6 +188,7 @@ private void InvokeFolderInner(Folder folder) if (folder.CreatedAgeDate != null && filesCount > 0) { var created = files.Min(f => f.CreationTime); + folder.Result.CreatedAge = created; Logger.LogInformation("folder '{Path}' most old created file is {Created}", path, created); if (created < folder.CreatedAgeDate) { @@ -196,6 +199,7 @@ private void InvokeFolderInner(Folder folder) if (folder.ModifiedAgeDate != null && filesCount > 0) { var modified = files.Min(f => f.LastWriteTime); + folder.Result.ModifiedAge = modified; Logger.LogInformation("folder '{Path}' most old modified file is {Created}", path, modified); if (modified < folder.ModifiedAgeDate) { diff --git a/generic jobs/HealthCheck/Endpoint.cs b/generic jobs/HealthCheck/Endpoint.cs index e936b0ba..9a9521c8 100644 --- a/generic jobs/HealthCheck/Endpoint.cs +++ b/generic jobs/HealthCheck/Endpoint.cs @@ -43,6 +43,8 @@ public Endpoint(IConfigurationSection section, Defaults defaults) : base(section //// -------------------------- //// + public EndpointResult Result { get; } = new(); + private static Uri? SetAbsoluteUrl(string url) { if (Uri.TryCreate(url, UriKind.Absolute, out var result)) { return result; } diff --git a/generic jobs/HealthCheck/EndpointResult.cs b/generic jobs/HealthCheck/EndpointResult.cs new file mode 100644 index 00000000..9a4de44f --- /dev/null +++ b/generic jobs/HealthCheck/EndpointResult.cs @@ -0,0 +1,8 @@ +using System.Net; + +namespace HealthCheck; + +internal class EndpointResult +{ + public HttpStatusCode HttpStatusCode { get; set; } +} \ No newline at end of file diff --git a/generic jobs/HealthCheck/Job.cs b/generic jobs/HealthCheck/Job.cs index 4cddd914..5c0ff87b 100644 --- a/generic jobs/HealthCheck/Job.cs +++ b/generic jobs/HealthCheck/Job.cs @@ -162,6 +162,7 @@ private async Task InvokeEndpointInner(Endpoint endpoint) throw new CheckException($"health check fail for endpoint name '{endpoint.Name}' with url '{uri}'. message: {ex.Message}"); } + endpoint.Result.HttpStatusCode = response.StatusCode; if (endpoint.SuccessStatusCodes.Any(s => s == (int)response.StatusCode)) { Logger.LogInformation("health check success for endpoint name '{EndpointName}' with url '{EndpointUrl}'", diff --git a/generic jobs/InfluxDBCheck/InfluxQuery.cs b/generic jobs/InfluxDBCheck/InfluxQuery.cs index 50ae7e20..5db4c9d9 100644 --- a/generic jobs/InfluxDBCheck/InfluxQuery.cs +++ b/generic jobs/InfluxDBCheck/InfluxQuery.cs @@ -22,4 +22,6 @@ internal class InfluxQuery(IConfigurationSection section, Defaults defaults) : public Condition? InternalValueCondition { get; set; } //// -------------------------- //// + + public InfluxQueryResult Result { get; } = new(); } \ No newline at end of file diff --git a/generic jobs/InfluxDBCheck/InfluxQueryResult.cs b/generic jobs/InfluxDBCheck/InfluxQueryResult.cs new file mode 100644 index 00000000..b2911838 --- /dev/null +++ b/generic jobs/InfluxDBCheck/InfluxQueryResult.cs @@ -0,0 +1,7 @@ +namespace InfluxDBCheck; + +internal class InfluxQueryResult +{ + public double? QueryValue { get; set; } + public int? QueryRecordsCount { get; set; } +} \ No newline at end of file diff --git a/generic jobs/InfluxDBCheck/Job.cs b/generic jobs/InfluxDBCheck/Job.cs index 889c7e3c..3a370767 100644 --- a/generic jobs/InfluxDBCheck/Job.cs +++ b/generic jobs/InfluxDBCheck/Job.cs @@ -6,7 +6,6 @@ using Newtonsoft.Json; using Planar.Job; using System.Globalization; -using System.Net; using System.Text; using System.Text.RegularExpressions; @@ -22,7 +21,7 @@ internal partial class Job : BaseCheckJob static partial void VetoQuery(InfluxQuery query); - static partial void Finalayze(IEnumerable endpoints); + static partial void Finalayze(IEnumerable queries); public override void Configure(IConfigurationBuilder configurationBuilder, IJobExecutionContext context) { @@ -139,6 +138,7 @@ private async Task InvokeQueryCheckInner(InfluxQuery query, InfluxProxy proxy) if (query.InternalValueCondition != null) { var value = GetValue(result, query.Name) ?? 0; + query.Result.QueryValue = value; var ok = query.InternalValueCondition.Evaluate(value); if (!ok) { @@ -150,7 +150,8 @@ private async Task InvokeQueryCheckInner(InfluxQuery query, InfluxProxy proxy) if (query.InternalRecordsCondition != null) { - var value = GetRecords(result); + var value = GetRecordsCount(result); + query.Result.QueryRecordsCount = value; var ok = query.InternalRecordsCondition.Evaluate(value); if (!ok) { @@ -164,7 +165,7 @@ private async Task InvokeQueryCheckInner(InfluxQuery query, InfluxProxy proxy) IncreaseEffectedRows(); } - private static double GetRecords(List tables) + private static int GetRecordsCount(List tables) { if (tables.Count == 0) { return 0; } var table = tables[0]; diff --git a/generic jobs/RabbitMQCheck/Job.cs b/generic jobs/RabbitMQCheck/Job.cs index eb3cc3a2..43c73c92 100644 --- a/generic jobs/RabbitMQCheck/Job.cs +++ b/generic jobs/RabbitMQCheck/Job.cs @@ -21,6 +21,10 @@ internal partial class Job : BaseCheckJob static partial void Finalayze(IEnumerable queues); + static partial void Finalayze(Node node); + + static partial void Finalayze(HealthCheck healthCheck); + public override void Configure(IConfigurationBuilder configurationBuilder, IJobExecutionContext context) { CustomConfigure(configurationBuilder, context); @@ -69,6 +73,8 @@ public async override Task ExecuteJob(IJobExecutionContext context) await Task.WhenAll(tasks); + Finalayze(healthCheck); + Finalayze(node); Finalayze(queues); Finalayze(); } @@ -187,6 +193,9 @@ private async Task InvokeNodeCheckInner(Node node, Server server, string host) var proxy = RabbitMqProxy.GetProxy(host, server, Logger); var details = await proxy.GetNodeDetails(); + + node.Result = details; + foreach (var item in details) { if (node.DiskFreeAlarm.GetValueOrDefault()) @@ -225,12 +234,14 @@ private async Task InvokeHealthCheck(HealthCheck healthCheck, Server server) } } - private async Task InvokeQueueCheckInner(Queue queue, IEnumerable details) + private async Task InvokeQueueCheckInner(Queue queue, IEnumerable details) { if (!queue.IsValid) { return; } var detail = details.FirstOrDefault(x => string.Equals(x.Name, queue.Name, StringComparison.OrdinalIgnoreCase)) ?? throw new CheckException($"queue '{queue.Name}' does not exists"); + queue.Result = detail; + CheckState(queue, detail); CheckConsumers(queue, detail); CheckMessages(queue, detail); @@ -240,7 +251,7 @@ private async Task InvokeQueueCheckInner(Queue queue, IEnumerable await Task.CompletedTask; } - private void CheckMemory(Queue queue, QueueDetails detail) + private void CheckMemory(Queue queue, QueueResult detail) { // Memory if (queue.MemoryNumber.HasValue) @@ -256,7 +267,7 @@ private void CheckMemory(Queue queue, QueueDetails detail) } } - private void CheckMessages(Queue queue, QueueDetails detail) + private void CheckMessages(Queue queue, QueueResult detail) { // Messages if (queue.Messages.HasValue) @@ -272,7 +283,7 @@ private void CheckMessages(Queue queue, QueueDetails detail) } } - private void CheckUnacked(Queue queue, QueueDetails detail) + private void CheckUnacked(Queue queue, QueueResult detail) { if (queue.Unacked.HasValue) { @@ -287,7 +298,7 @@ private void CheckUnacked(Queue queue, QueueDetails detail) } } - private void CheckConsumers(Queue queue, QueueDetails detail) + private void CheckConsumers(Queue queue, QueueResult detail) { // Consumers if (queue.Consumers.HasValue) @@ -303,7 +314,7 @@ private void CheckConsumers(Queue queue, QueueDetails detail) } } - private void CheckState(Queue queue, QueueDetails detail) + private void CheckState(Queue queue, QueueResult detail) { // Check State if (queue.CheckState.GetValueOrDefault()) diff --git a/generic jobs/RabbitMQCheck/Node.cs b/generic jobs/RabbitMQCheck/Node.cs index 0dc2045b..68718eae 100644 --- a/generic jobs/RabbitMQCheck/Node.cs +++ b/generic jobs/RabbitMQCheck/Node.cs @@ -10,4 +10,6 @@ internal class Node(IConfigurationSection section, Defaults defaults) : BaseDefa public bool IsValid => MemoryAlarm.GetValueOrDefault() || DiskFreeAlarm.GetValueOrDefault(); public string Key => "[nodes]"; + + public IEnumerable Result { get; set; } = []; } \ No newline at end of file diff --git a/generic jobs/RabbitMQCheck/NodeDetails.cs b/generic jobs/RabbitMQCheck/NodeResult.cs similarity index 95% rename from generic jobs/RabbitMQCheck/NodeDetails.cs rename to generic jobs/RabbitMQCheck/NodeResult.cs index fe334adc..ad0bd26a 100644 --- a/generic jobs/RabbitMQCheck/NodeDetails.cs +++ b/generic jobs/RabbitMQCheck/NodeResult.cs @@ -2,7 +2,7 @@ namespace RabbitMQCheck; -internal class NodeDetails +internal class NodeResult { [JsonProperty("disk_free")] public long DiskFree { get; set; } diff --git a/generic jobs/RabbitMQCheck/Queue.cs b/generic jobs/RabbitMQCheck/Queue.cs index e387c05c..060b18a5 100644 --- a/generic jobs/RabbitMQCheck/Queue.cs +++ b/generic jobs/RabbitMQCheck/Queue.cs @@ -14,4 +14,6 @@ internal class Queue(IConfigurationSection section, Defaults defaults) : BaseDef public long? MemoryNumber { get; private set; } = CommonUtil.GetSize(section.GetValue("memory"), "memory"); public string Key => Name; public bool IsValid => Messages.HasValue || Consumers.HasValue || CheckState.HasValue || MemoryNumber.HasValue; + + public QueueResult Result { get; set; } = new(); } \ No newline at end of file diff --git a/generic jobs/RabbitMQCheck/QueueDetails.cs b/generic jobs/RabbitMQCheck/QueueResult.cs similarity index 98% rename from generic jobs/RabbitMQCheck/QueueDetails.cs rename to generic jobs/RabbitMQCheck/QueueResult.cs index 0ef709ed..1b98a713 100644 --- a/generic jobs/RabbitMQCheck/QueueDetails.cs +++ b/generic jobs/RabbitMQCheck/QueueResult.cs @@ -2,7 +2,7 @@ namespace RabbitMQCheck; -public class QueueDetails +public class QueueResult { public string Name { get; set; } = null!; public int Messages { get; set; } diff --git a/generic jobs/RabbitMQCheck/RabbitMqProxy.cs b/generic jobs/RabbitMQCheck/RabbitMqProxy.cs index 45d28812..cf403dbc 100644 --- a/generic jobs/RabbitMQCheck/RabbitMqProxy.cs +++ b/generic jobs/RabbitMQCheck/RabbitMqProxy.cs @@ -59,11 +59,11 @@ public async Task VirtualHosts() await Alarm("virtual hosts", "virtual-hosts"); } - public async Task> GetNodeDetails() + public async Task> GetNodeDetails() { const string resource = "api/nodes"; var request = new RestRequest(resource, Method.Get); - var response = await _restClient.ExecuteAsync>(request); + var response = await _restClient.ExecuteAsync>(request); if (!response.IsSuccessful) { throw new CheckException($"node check on url {resource} failed. status code {response.StatusCode}", response.ErrorException); @@ -72,11 +72,11 @@ public async Task> GetNodeDetails() return response.Data ?? []; } - public async Task> GetQueueDetails() + public async Task> GetQueueDetails() { const string resource = "api/queues"; var request = new RestRequest(resource, Method.Get); - var response = await _restClient.ExecuteAsync>(request); + var response = await _restClient.ExecuteAsync>(request); if (!response.IsSuccessful) { throw new CheckException($"queue check on url {resource} failed. status code {response.StatusCode}", response.ErrorException); diff --git a/generic jobs/RedisCheck/Job.cs b/generic jobs/RedisCheck/Job.cs index 328ba8a5..0bb354ad 100644 --- a/generic jobs/RedisCheck/Job.cs +++ b/generic jobs/RedisCheck/Job.cs @@ -21,6 +21,8 @@ internal partial class Job : BaseCheckJob static partial void Finalayze(IEnumerable keys); + static partial void Finalayze(HealthCheck healthCheck); + public override void Configure(IConfigurationBuilder configurationBuilder, IJobExecutionContext context) { CustomConfigure(configurationBuilder, context); @@ -58,6 +60,7 @@ public async override Task ExecuteJob(IJobExecutionContext context) await SafeInvokeCheck(healthCheck, InvokeHealthCheckInner); await SafeInvokeCheck(keys, InvokeKeyCheckInner); + Finalayze(healthCheck); Finalayze(keys); Finalayze(); } @@ -215,7 +218,9 @@ private async Task InvokeHealthCheckInner(HealthCheck healthCheck) private async Task InvokeKeyCheckInner(RedisKey key) { - if (!await RedisFactory.Exists(key)) + var exists = await RedisFactory.Exists(key); + key.Result.Exists = exists; + if (key.Exists.GetValueOrDefault() && !exists) { throw new CheckException($"key '{key.Key}' is not exists"); } @@ -225,12 +230,14 @@ private async Task InvokeKeyCheckInner(RedisKey key) if (key.Length > 0) { length = await RedisFactory.GetLength(key); + key.Result.Length = length; Logger.LogInformation("key '{Key}' length is {Length:N0}", key.Key, length); } if (key.MemoryUsageNumber > 0) { size = await RedisFactory.GetMemoryUsage(key); + key.Result.MemoryUsage = size; Logger.LogInformation("key '{Key}' size is {Size:N0} byte(s)", key.Key, size); } diff --git a/generic jobs/RedisCheck/RedisKey.cs b/generic jobs/RedisCheck/RedisKey.cs index 49c41c2d..c03de36b 100644 --- a/generic jobs/RedisCheck/RedisKey.cs +++ b/generic jobs/RedisCheck/RedisKey.cs @@ -8,7 +8,7 @@ internal class RedisKey(IConfigurationSection section, Defaults defaults) : Base { public string Key { get; } = section.GetValue("key") ?? string.Empty; public string? MemoryUsage { get; } = section.GetValue("memory usage"); - public int? Length { get; } = section.GetValue("length"); + public long? Length { get; } = section.GetValue("length"); public int? Database { get; } = section.GetValue("database"); public bool? Exists { get; } = section.GetValue("exists"); @@ -19,6 +19,8 @@ internal class RedisKey(IConfigurationSection section, Defaults defaults) : Base //// --------------------------------------- //// + public RedisKeyResult Result { get; } = new(); + private static int? GetSize(string? source, string fieldName) { var factor = 0; diff --git a/generic jobs/RedisCheck/RedisKeyResult.cs b/generic jobs/RedisCheck/RedisKeyResult.cs new file mode 100644 index 00000000..9b09093c --- /dev/null +++ b/generic jobs/RedisCheck/RedisKeyResult.cs @@ -0,0 +1,8 @@ +namespace RedisCheck; + +internal class RedisKeyResult +{ + public long? MemoryUsage { get; set; } + public long? Length { get; set; } + public bool? Exists { get; set; } +} \ No newline at end of file diff --git a/generic jobs/WindowsServiceCheck/Job.cs b/generic jobs/WindowsServiceCheck/Job.cs index e69b558e..67a956ce 100644 --- a/generic jobs/WindowsServiceCheck/Job.cs +++ b/generic jobs/WindowsServiceCheck/Job.cs @@ -113,13 +113,16 @@ private void InvokeServiceInner(Service service) { if (string.IsNullOrWhiteSpace(service.Host)) { - throw new CheckException($"service '{service.Name}' has no host name (null or empty)"); + throw new CheckException($"service '{service.Name}' has no host. (missing host group name '{service.HostGroupName}'"); } using var controller = new ServiceController(service.Name, service.Host); var status = controller.Status; var startType = controller.StartType; var disabled = status == ServiceControllerStatus.Stopped && startType == ServiceStartMode.Disabled; + + service.Result.Disabled = disabled; + if (disabled && service.IgnoreDisabled) { Logger.LogInformation("skipping disabled service '{Name}' on host '{Host}'", service.Name, service.Host); @@ -131,6 +134,8 @@ private void InvokeServiceInner(Service service) throw new CheckException($"service '{service.Name}' on host '{service.Host}' is in {status} start type"); } + service.Result.AutoStartMode = startType == ServiceStartMode.Automatic; + if (startType == ServiceStartMode.Manual && service.AutoStartMode) { throw new CheckException($"service '{service.Name}' start type is {nameof(ServiceStartMode.Manual)}"); @@ -174,6 +179,7 @@ private void InvokeServiceInner(Service service) status = controller.Status; if (status == ServiceControllerStatus.Running) { + service.Result.Started = true; Logger.LogInformation("service '{Name}' on host '{Host}' is in running status", service.Name, service.Host); IncreaseEffectedRows(); return; diff --git a/generic jobs/WindowsServiceCheck/Service.cs b/generic jobs/WindowsServiceCheck/Service.cs index 3ec1fb4d..690bf02b 100644 --- a/generic jobs/WindowsServiceCheck/Service.cs +++ b/generic jobs/WindowsServiceCheck/Service.cs @@ -29,11 +29,13 @@ public Service(Service service) : base(service) public string? HostGroupName { get; } public bool IgnoreDisabled { get; } public bool StartService { get; } - public bool AutoStartMode { get; } + public bool AutoStartMode { get; }` public TimeSpan StartServiceTimeout { get; } public string Key => Name; //// --------------------------------------- //// + public ServiceResult Result { get; } = new(); + public string? Host { get; set; } } \ No newline at end of file diff --git a/generic jobs/WindowsServiceCheck/ServiceResult.cs b/generic jobs/WindowsServiceCheck/ServiceResult.cs new file mode 100644 index 00000000..07497ea1 --- /dev/null +++ b/generic jobs/WindowsServiceCheck/ServiceResult.cs @@ -0,0 +1,8 @@ +namespace WindowsServiceCheck; + +internal class ServiceResult +{ + public bool Disabled { get; set; } + public bool AutoStartMode { get; set; } + public bool Started { get; set; } +} \ No newline at end of file