From d8fd6d13f9d8f3c9e441130ea8760bb6e6cd85ce Mon Sep 17 00:00:00 2001 From: Chris Kaczor Date: Sat, 27 Jan 2024 15:57:01 -0500 Subject: [PATCH] Upgrade DeviceStatus service to .NET 8 and add OpenTelemetry --- .../Service/Controllers/StatusController.cs | 27 ++++----- DeviceStatus/Service/Device.cs | 16 +++--- DeviceStatus/Service/DeviceRepository.cs | 4 +- DeviceStatus/Service/Dockerfile | 6 +- DeviceStatus/Service/LaundryMonitor.cs | 15 ++--- DeviceStatus/Service/MessageHandler.cs | 55 +++++++++--------- DeviceStatus/Service/Program.cs | 57 +++++++++++-------- DeviceStatus/Service/Service.csproj | 14 ++--- DeviceStatus/Service/appsettings.json | 7 ++- DeviceStatus/Service/deploy/manifest.yaml | 4 +- 10 files changed, 101 insertions(+), 104 deletions(-) diff --git a/DeviceStatus/Service/Controllers/StatusController.cs b/DeviceStatus/Service/Controllers/StatusController.cs index 2608c35..8f84914 100644 --- a/DeviceStatus/Service/Controllers/StatusController.cs +++ b/DeviceStatus/Service/Controllers/StatusController.cs @@ -1,21 +1,14 @@ using Microsoft.AspNetCore.Mvc; -namespace Service.Controllers -{ - [Route("[controller]")] - [ApiController] - public class StatusController : ControllerBase - { - private readonly DeviceRepository _deviceRepository; - public StatusController(DeviceRepository deviceRepository) - { - _deviceRepository = deviceRepository; - } +namespace ChrisKaczor.HomeMonitor.DeviceStatus.Service.Controllers; - [HttpGet("recent")] - public ActionResult> GetRecent() - { - return _deviceRepository.Values; - } +[Route("[controller]")] +[ApiController] +public class StatusController(DeviceRepository deviceRepository) : ControllerBase +{ + [HttpGet("recent")] + public ActionResult> GetRecent() + { + return deviceRepository.Values; } -} +} \ No newline at end of file diff --git a/DeviceStatus/Service/Device.cs b/DeviceStatus/Service/Device.cs index 3eb89e1..006b479 100644 --- a/DeviceStatus/Service/Device.cs +++ b/DeviceStatus/Service/Device.cs @@ -1,22 +1,22 @@ using System.Text.Json.Serialization; -namespace Service; +namespace ChrisKaczor.HomeMonitor.DeviceStatus.Service; public class Device { - [JsonPropertyName("name")] - public string Name { get; } - - [JsonPropertyName("status")] - public bool Status { get; private set; } - public Device(string name, string statusString) { Name = name; Update(statusString); } - public void Update(string statusString) + [JsonPropertyName("name")] + public string Name { get; } + + [JsonPropertyName("status")] + public bool Status { get; private set; } + + private void Update(string statusString) { Status = statusString == "1"; } diff --git a/DeviceStatus/Service/DeviceRepository.cs b/DeviceStatus/Service/DeviceRepository.cs index 6f5dae6..f7bd75f 100644 --- a/DeviceStatus/Service/DeviceRepository.cs +++ b/DeviceStatus/Service/DeviceRepository.cs @@ -1,3 +1,3 @@ -namespace Service; +namespace ChrisKaczor.HomeMonitor.DeviceStatus.Service; -public class DeviceRepository : Dictionary { } \ No newline at end of file +public class DeviceRepository : Dictionary; \ No newline at end of file diff --git a/DeviceStatus/Service/Dockerfile b/DeviceStatus/Service/Dockerfile index 3544536..2a99a76 100644 --- a/DeviceStatus/Service/Dockerfile +++ b/DeviceStatus/Service/Dockerfile @@ -1,8 +1,8 @@ -FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine AS base +FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine AS base WORKDIR /app -EXPOSE 80 +EXPOSE 8080 -FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build WORKDIR /src COPY ["./Service.csproj", "./"] RUN dotnet restore "Service.csproj" diff --git a/DeviceStatus/Service/LaundryMonitor.cs b/DeviceStatus/Service/LaundryMonitor.cs index 6badf90..dc9a539 100644 --- a/DeviceStatus/Service/LaundryMonitor.cs +++ b/DeviceStatus/Service/LaundryMonitor.cs @@ -1,20 +1,13 @@ using RestSharp; -namespace Service; +namespace ChrisKaczor.HomeMonitor.DeviceStatus.Service; -public class LaundryMonitor +public class LaundryMonitor(IConfiguration configuration) { + private readonly string _botToken = configuration["Telegram:BotToken"]!; + private readonly string _chatId = configuration["Telegram:ChatId"]!; private readonly RestClient _restClient = new(); - private readonly string _botToken; - private readonly string _chatId; - - public LaundryMonitor(IConfiguration configuration) - { - _botToken = configuration["Telegram:BotToken"]; - _chatId = configuration["Telegram:ChatId"]; - } - public async Task HandleDeviceMessage(Device device) { try diff --git a/DeviceStatus/Service/MessageHandler.cs b/DeviceStatus/Service/MessageHandler.cs index a3b9cd1..7ddbad6 100644 --- a/DeviceStatus/Service/MessageHandler.cs +++ b/DeviceStatus/Service/MessageHandler.cs @@ -3,33 +3,34 @@ using MQTTnet; using MQTTnet.Client; using System.Text.Json; -namespace Service; +namespace ChrisKaczor.HomeMonitor.DeviceStatus.Service; public class MessageHandler : IHostedService { - private IMqttClient? _mqttClient; - private HubConnection? _hubConnection; - private readonly IConfiguration _configuration; - private readonly DeviceRepository _deviceRepository; - private readonly LaundryMonitor _laundryMonitor; - private readonly Dictionary _deviceTimers = new(); + private readonly ILogger _logger; private readonly TimeSpan _deviceDelayTime; + private readonly DeviceRepository _deviceRepository; + private readonly Dictionary _deviceTimers = new(); + private readonly LaundryMonitor _laundryMonitor; + private HubConnection? _hubConnection; + private IMqttClient? _mqttClient; - public MessageHandler(IConfiguration configuration, DeviceRepository deviceRepository, LaundryMonitor laundryMonitor) + public MessageHandler(IConfiguration configuration, DeviceRepository deviceRepository, LaundryMonitor laundryMonitor, ILogger logger) { _configuration = configuration; + _logger = logger; _deviceRepository = deviceRepository; _laundryMonitor = laundryMonitor; - _deviceDelayTime = TimeSpan.Parse(_configuration["DeviceStatus:DelayTime"]); + _deviceDelayTime = TimeSpan.Parse(_configuration["DeviceStatus:DelayTime"]!); } public async Task StartAsync(CancellationToken cancellationToken) { if (!string.IsNullOrEmpty(_configuration["Hub:DeviceStatus"])) { - _hubConnection = new HubConnectionBuilder().WithUrl(_configuration["Hub:DeviceStatus"]).Build(); + _hubConnection = new HubConnectionBuilder().WithUrl(_configuration["Hub:DeviceStatus"]!).Build(); _hubConnection.On("RequestLatestStatus", async () => await RequestLatestStatus()); await _hubConnection.StartAsync(cancellationToken); @@ -45,16 +46,21 @@ public class MessageHandler : IHostedService await _mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None); var mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder() - .WithTopicFilter( - f => - { - f.WithTopic("device-status/#"); - }) + .WithTopicFilter(f => f.WithTopic("device-status/#")) .Build(); await _mqttClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None); } + public async Task StopAsync(CancellationToken cancellationToken) + { + if (_hubConnection != null) + await _hubConnection.StopAsync(cancellationToken); + + if (_mqttClient != null) + await _mqttClient.DisconnectAsync(new MqttClientDisconnectOptionsBuilder().Build(), CancellationToken.None); + } + private async Task OnApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg) { var topic = arg.ApplicationMessage.Topic; @@ -65,8 +71,8 @@ public class MessageHandler : IHostedService var newDevice = new Device(deviceName, payload); - if (_deviceTimers.ContainsKey(newDevice.Name)) - await _deviceTimers[newDevice.Name].DisposeAsync(); + if (_deviceTimers.TryGetValue(newDevice.Name, out var deviceTimer)) + await deviceTimer.DisposeAsync(); if (!_deviceRepository.ContainsKey(newDevice.Name) || newDevice.Status) { @@ -95,7 +101,7 @@ public class MessageHandler : IHostedService private async void OnDeviceTimer(object? state) { - var device = (Device)state!; + var device = (Device) state!; await HandleDeviceMessage(device); @@ -141,17 +147,8 @@ public class MessageHandler : IHostedService } } - public async Task StopAsync(CancellationToken cancellationToken) + private void WriteLog(string message) { - if (_hubConnection != null) - await _hubConnection.StopAsync(cancellationToken); - - if (_mqttClient != null) - await _mqttClient.DisconnectAsync(new MqttClientDisconnectOptionsBuilder().Build(), CancellationToken.None); - } - - private static void WriteLog(string message) - { - Console.WriteLine(message); + _logger.LogInformation(message); } } \ No newline at end of file diff --git a/DeviceStatus/Service/Program.cs b/DeviceStatus/Service/Program.cs index 7615777..3ceb657 100644 --- a/DeviceStatus/Service/Program.cs +++ b/DeviceStatus/Service/Program.cs @@ -1,29 +1,40 @@ -using Service; +using ChrisKaczor.Common.OpenTelemetry; +using System.Reflection; -var builder = WebApplication.CreateBuilder(args); +namespace ChrisKaczor.HomeMonitor.DeviceStatus.Service; -builder.Host.ConfigureAppConfiguration((_, config) => config.AddEnvironmentVariables()); - -builder.Services.AddControllers(); - -builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); - -builder.Services.AddHostedService(); - -builder.Services.AddSingleton(); -builder.Services.AddSingleton(); - -var app = builder.Build(); - -if (app.Environment.IsDevelopment()) +public static class Program { - app.UseSwagger(); - app.UseSwaggerUI(); -} + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); -app.UseAuthorization(); + builder.Configuration.AddEnvironmentVariables(); -app.MapControllers(); + builder.Services.AddCommonOpenTelemetry(Assembly.GetExecutingAssembly().GetName().Name, builder.Configuration["Telemetry:Endpoint"], nameof(MessageHandler)); -app.Run(); \ No newline at end of file + builder.Services.AddControllers(); + + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(); + + builder.Services.AddHostedService(); + + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + + var app = builder.Build(); + + if (app.Environment.IsDevelopment()) + { + app.UseSwagger(); + app.UseSwaggerUI(); + } + + app.UseAuthorization(); + + app.MapControllers(); + + app.Run(); + } +} \ No newline at end of file diff --git a/DeviceStatus/Service/Service.csproj b/DeviceStatus/Service/Service.csproj index f60989e..fb03459 100644 --- a/DeviceStatus/Service/Service.csproj +++ b/DeviceStatus/Service/Service.csproj @@ -1,19 +1,19 @@ - net6.0 + net8.0 enable enable ChrisKaczor.HomeMonitor.DeviceStatus.Service + ChrisKaczor.HomeMonitor.DeviceStatus.Service - - - - - - + + + + + diff --git a/DeviceStatus/Service/appsettings.json b/DeviceStatus/Service/appsettings.json index c4f0575..8814c7c 100644 --- a/DeviceStatus/Service/appsettings.json +++ b/DeviceStatus/Service/appsettings.json @@ -1,8 +1,8 @@ { "Logging": { "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Default": "Warning", + "Microsoft": "Information" } }, "AllowedHosts": "*", @@ -18,5 +18,8 @@ }, "Mqtt": { "Server": "mosquitto" + }, + "Telemetry": { + "Endpoint": "http://signoz-otel-collector.platform:4317/" } } diff --git a/DeviceStatus/Service/deploy/manifest.yaml b/DeviceStatus/Service/deploy/manifest.yaml index cb1a578..1b4c3c2 100644 --- a/DeviceStatus/Service/deploy/manifest.yaml +++ b/DeviceStatus/Service/deploy/manifest.yaml @@ -51,7 +51,7 @@ metadata: spec: ports: - name: client - port: 80 + port: 8080 selector: app: device-status-service type: ClusterIP @@ -75,7 +75,7 @@ spec: - kind: Service name: device-status-service namespace: home-monitor - port: 80 + port: 8080 --- apiVersion: traefik.containo.us/v1alpha1 kind: Middleware