Логирование, багфиксы, добавил мониторин /proc/mdstat. Юнит для systemd
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ini-parser" Version="2.5.2" />
|
||||
<PackageReference Include="NLog" Version="4.7.4" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
using NLog;
|
||||
|
||||
namespace Barsik
|
||||
{
|
||||
public static class Logging
|
||||
{
|
||||
public static void Setup()
|
||||
{
|
||||
var config = new NLog.Config.LoggingConfiguration();
|
||||
|
||||
var logConsole = new NLog.Targets.ConsoleTarget("logconsole");
|
||||
config.AddRuleForAllLevels(logConsole);
|
||||
LogManager.Configuration = config;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using IniParser.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Barsik
|
||||
{
|
||||
/// <summary>
|
||||
/// Monitors configured RAID array status via /proc/mdstat
|
||||
/// Will fill registers info starting from baseAddress with
|
||||
/// disk status (0 - fail, 1 - up) in following order:
|
||||
/// raid #0 disk #0
|
||||
/// raid #0 disk #1
|
||||
/// ...
|
||||
/// raid #0 disk #N
|
||||
/// raid #1 disk #0
|
||||
/// ...
|
||||
/// etc
|
||||
/// </summary>
|
||||
class MDStatMonitoringUnit : BaseMonitoringUnit
|
||||
{
|
||||
public MDStatMonitoringUnit(SectionData config, RegistersContainer registers) : base(config, registers)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
int currentAddress = baseAddress;
|
||||
// the file is not so big, so read it completely
|
||||
var lines = File.ReadAllLines("/proc/mdstat");
|
||||
for (int i = 0; i < lines.Length;)
|
||||
{
|
||||
if (lines[i].StartsWith("md") && i < lines.Length - 1)
|
||||
{
|
||||
// we found device description
|
||||
// second line of it is as follows:
|
||||
// 2930264896 blocks super 1.0 [2/2] [UU]
|
||||
// we need last characters in brackets []
|
||||
currentAddress += FillDiskStatus(currentAddress, lines[i + 1]);
|
||||
i += 2;
|
||||
}
|
||||
else i++;
|
||||
}
|
||||
Thread.Sleep(2000);
|
||||
}
|
||||
}
|
||||
|
||||
private int FillDiskStatus(int address, string v)
|
||||
{
|
||||
int last_pos = v.LastIndexOf(']');
|
||||
int pos;
|
||||
for (pos = last_pos; pos > 0 && v[pos] != '['; pos--) ;
|
||||
if (v[pos] != '[') return 0;
|
||||
for (int i = pos + 1; i < last_pos; i++)
|
||||
{
|
||||
if (v[i] == 'U') registers[address + i - (pos + 1)] = 1;
|
||||
else registers[address + i - (pos + 1)] = 1;
|
||||
}
|
||||
return last_pos - pos - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
-6
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
@@ -20,11 +21,14 @@ namespace Barsik
|
||||
|
||||
internal void Run()
|
||||
{
|
||||
var logger = LogManager.GetCurrentClassLogger();
|
||||
logger.Info("Accepting connections on port " + Port);
|
||||
var listener = new TcpListener(IPAddress.Any, Port);
|
||||
listener.Start();
|
||||
while (true)
|
||||
{
|
||||
var client = listener.AcceptTcpClient();
|
||||
logger.Info("Accepted connection from " + client.Client.RemoteEndPoint);
|
||||
var worker = new ModbusServerWorker(registers, client);
|
||||
Thread clientThread = new Thread(new ThreadStart(worker.Run));
|
||||
clientThread.Start();
|
||||
@@ -38,6 +42,7 @@ namespace Barsik
|
||||
|
||||
private RegistersContainer registers;
|
||||
private TcpClient client;
|
||||
private static Logger logger = LogManager.GetCurrentClassLogger();
|
||||
public ModbusServerWorker(RegistersContainer registers, TcpClient client)
|
||||
{
|
||||
this.registers = registers;
|
||||
@@ -52,6 +57,7 @@ namespace Barsik
|
||||
|
||||
public void Run()
|
||||
{
|
||||
logger.Debug("Working with client");
|
||||
received = new List<byte>();
|
||||
try
|
||||
{
|
||||
@@ -63,11 +69,13 @@ namespace Barsik
|
||||
readCompleted.Reset();
|
||||
stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(this.OnReadCompleted), this);
|
||||
readCompleted.WaitOne();
|
||||
if (currentReceived < 0)
|
||||
if (currentReceived <= 0)
|
||||
{
|
||||
logger.Debug("Received no data, closing ");
|
||||
client.Close();
|
||||
return;
|
||||
}
|
||||
logger.Debug("ProcessReceivedData of " + received.Count);
|
||||
ProcessReceivedData();
|
||||
}
|
||||
}
|
||||
@@ -75,6 +83,11 @@ namespace Barsik
|
||||
{
|
||||
client.Close();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (stream != null) stream.Dispose();
|
||||
client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessReceivedData()
|
||||
@@ -123,12 +136,20 @@ namespace Barsik
|
||||
|
||||
private void OnReadCompleted(IAsyncResult ar)
|
||||
{
|
||||
currentReceived = stream.EndRead(ar);
|
||||
lock (received)
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < currentReceived; i++) received.Add(buffer[i]);
|
||||
currentReceived = stream.EndRead(ar);
|
||||
lock (received)
|
||||
{
|
||||
for (int i = 0; i < currentReceived; i++) received.Add(buffer[i]);
|
||||
}
|
||||
readCompleted.Set();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
logger.Info("Error receiving " + e);
|
||||
currentReceived = -1;
|
||||
}
|
||||
readCompleted.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-59
@@ -1,8 +1,5 @@
|
||||
using IniParser.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Barsik
|
||||
{
|
||||
@@ -31,66 +28,15 @@ namespace Barsik
|
||||
{
|
||||
return new SensorsMonitoringUnit(config, registers);
|
||||
}
|
||||
else
|
||||
else if (type == "MDStat")
|
||||
{
|
||||
return new MDStatMonitoringUnit(config, registers);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Unknown unit type " + type);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SensorsMonitoringUnit : BaseMonitoringUnit
|
||||
{
|
||||
public SensorsMonitoringUnit(SectionData config, RegistersContainer registers) : base(config, registers)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
var stringToFind = config.Keys["String"];
|
||||
var multiplier = float.Parse(config.Keys["Multiplier"]);
|
||||
while (true)
|
||||
{
|
||||
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("sensors");
|
||||
procStartInfo.RedirectStandardOutput = true;
|
||||
procStartInfo.UseShellExecute = false;
|
||||
procStartInfo.CreateNoWindow = true;
|
||||
System.Diagnostics.Process proc = new System.Diagnostics.Process();
|
||||
proc.StartInfo = procStartInfo;
|
||||
proc.Start();
|
||||
while (!proc.HasExited)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
string result = proc.StandardOutput.ReadToEnd();
|
||||
var lines = result.Split('\n');
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
{
|
||||
if (lines[i].Contains(stringToFind))
|
||||
{
|
||||
var value = ExtractValue(lines[i]);
|
||||
registers[baseAddress] = (int)(value * multiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Good(char c)
|
||||
{
|
||||
if (c == '-' || c == '+' || c == '.') return true;
|
||||
if (c >= '0' && c <= '9') return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private float ExtractValue(string v)
|
||||
{
|
||||
int pos = 0;
|
||||
while (pos < v.Length && !Good(v[pos])) pos++;
|
||||
int pos2 = pos;
|
||||
while (pos2 < v.Length && Good(v[pos2])) pos2++;
|
||||
float res = 0;
|
||||
float.TryParse(v.Substring(pos, pos2 - pos), out res);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-10
@@ -1,6 +1,8 @@
|
||||
using IniParser;
|
||||
using System;
|
||||
using NLog;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
|
||||
namespace Barsik
|
||||
@@ -10,14 +12,20 @@ namespace Barsik
|
||||
private static RegistersContainer registers;
|
||||
private static List<BaseMonitoringUnit> units;
|
||||
|
||||
static void Main(string[] args)
|
||||
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Logging.Setup();
|
||||
logger.Info("Barsik monitoring service starting");
|
||||
|
||||
registers = new RegistersContainer();
|
||||
var server = new ModbusServer(registers);
|
||||
units = new List<BaseMonitoringUnit>();
|
||||
|
||||
var configParser = new FileIniDataParser();
|
||||
var data = configParser.ReadFile("barsik.ini");
|
||||
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
var data = configParser.ReadFile(Path.Combine(assemblyFolder, "barsik.ini"));
|
||||
foreach (var section in data.Sections)
|
||||
{
|
||||
if (section.SectionName.StartsWith("Unit"))
|
||||
@@ -31,12 +39,10 @@ namespace Barsik
|
||||
}
|
||||
}
|
||||
}
|
||||
server.Port = int.Parse(data["Server"]["Port"]);
|
||||
while (true)
|
||||
{
|
||||
server.Run();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
logger.Info("Configuration loaded, we have " + units.Count + " units");
|
||||
server.Port = int.Parse(data["Server"]["Port"]);
|
||||
server.Run();
|
||||
logger.Info("Exiting");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<PublishDir>bin\Debug\netcoreapp2.1\publish\</PublishDir>
|
||||
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||
<SelfContained>true</SelfContained>
|
||||
<_IsPortable>false</_IsPortable>
|
||||
<SelfContained>false</SelfContained>
|
||||
<_IsPortable>true</_IsPortable>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,88 @@
|
||||
using IniParser.Model;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Barsik
|
||||
{
|
||||
/// <summary>
|
||||
/// Parses output of "sensors" command and puts CPU core temperatures into
|
||||
/// registers
|
||||
/// </summary>
|
||||
class SensorsMonitoringUnit : BaseMonitoringUnit
|
||||
{
|
||||
const string CORE_STR = "Core{0} Temp:";
|
||||
|
||||
public SensorsMonitoringUnit(SectionData config, RegistersContainer registers) : base(config, registers)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
int cores = int.Parse(config.Keys["Cores"]);
|
||||
var multiplier = float.Parse(config.Keys["Multiplier"]);
|
||||
while (true)
|
||||
{
|
||||
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("sensors");
|
||||
procStartInfo.RedirectStandardOutput = true;
|
||||
procStartInfo.UseShellExecute = false;
|
||||
procStartInfo.CreateNoWindow = true;
|
||||
using (System.Diagnostics.Process proc = new System.Diagnostics.Process())
|
||||
{
|
||||
proc.StartInfo = procStartInfo;
|
||||
proc.Start();
|
||||
while (!proc.HasExited)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
string result = proc.StandardOutput.ReadToEnd();
|
||||
var lines = result.Split('\n');
|
||||
// lines in output will be of format:
|
||||
// Core0 Temp: +29.0°C
|
||||
// and there could be several lines for one core
|
||||
// so let's take all of them and use maximal value as core temp
|
||||
float[] t = new float[cores];
|
||||
for (int i = 0; i < cores; i++)
|
||||
{
|
||||
t[i] = 0;
|
||||
}
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
{
|
||||
for (int j = 0; j < cores; j++)
|
||||
{
|
||||
string toFind = string.Format(CORE_STR, j);
|
||||
if (lines[i].Contains(toFind))
|
||||
{
|
||||
var value = ExtractValue(lines[i].Substring(toFind.Length));
|
||||
t[j] = Math.Max(t[j], value);
|
||||
}
|
||||
}
|
||||
}
|
||||
// fill register data starting from baseAddress
|
||||
for (int i = 0; i < cores; i++)
|
||||
{
|
||||
registers[baseAddress + i] = (int)(t[i] * multiplier);
|
||||
}
|
||||
}
|
||||
Thread.Sleep(2000);
|
||||
}
|
||||
}
|
||||
|
||||
bool Good(char c)
|
||||
{
|
||||
if (c == '-' || c == '+' || c == '.') return true;
|
||||
if (c >= '0' && c <= '9') return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private float ExtractValue(string v)
|
||||
{
|
||||
int pos = 0;
|
||||
while (pos < v.Length && !Good(v[pos])) pos++;
|
||||
int pos2 = pos;
|
||||
while (pos2 < v.Length && Good(v[pos2])) pos2++;
|
||||
float res;
|
||||
float.TryParse(v.Substring(pos, pos2 - pos), out res);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -4,5 +4,9 @@ Port = 4500
|
||||
[Unit_CPU]
|
||||
Type = Sensors
|
||||
BaseAddress = 1
|
||||
String = CPU Temperature
|
||||
Multiplier = 100
|
||||
Cores = 2
|
||||
|
||||
[Unit_RAID]
|
||||
Type = MDStat
|
||||
BaseAddress = 3
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Barsik monitoring service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=dotnet /root/barsik/Barsik.dll
|
||||
User=root
|
||||
Group=root
|
||||
RuntimeDirectory=/root/barsik
|
||||
RuntimeDirectoryMode=0755
|
||||
ProtectHome=false
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user