Ovaj projekat predstavlja Proof of Concept (POC) rješenje razvijeno u .NET 10 okviru za praćenje sistemskih metrika Linux servera i njihovo izlaganje u JSON i XML formatima radi integracije sa Skyline DataMiner Cube platformom.
Aplikacija je dizajnirana po principima čiste arhitekture (Clean Architecture) i SOLID principa, pri čemu su svi slojevi organizovani unutar jednog .NET projekta radi jednostavnosti i lakšeg održavanja.
Struktura projekta je podijeljena po logičkim cjelinama (slojevima):
LinuxServerDataminerPOC/
├── Domain/
│ ├── Entities/
│ │ └── ServerMetrics.cs
│ └── Interfaces/
│ └── ILinuxMetricsCollector.cs
├── Application/
│ ├── Dtos/
│ │ └── ServerMetricsDto.cs
│ ├── Options/
│ │ └── MetricsOptions.cs
│ ├── Interfaces/
│ │ └── IMetricsService.cs
│ └── Services/
│ └── MetricsService.cs
├── Infrastructure/
│ ├── Collectors/
│ │ └── RealLinuxMetricsCollector.cs
│ └── Health/
│ └── ServerHealthCheck.cs
├── Properties/
│ └── launchSettings.json
├── appsettings.json
├── Program.cs
└── LinuxServerDataminerPOC.csproj
Domain sloj predstavlja srce aplikacije i ne zavisi niti od jedne vanjske biblioteke ili tehnologije.
Domain/Entities/ServerMetrics.cs
- Uloga: Entitet koji definira osnovne sirove podatke o stanju servera (CPU procenat, ukupna i iskorištena memorija u MB, procenat diska, uptime i vremenska oznaka).
- Zašto radi: Koristi C#
recordtip radi nepromjenjivosti (immutability) i sigurnosti obrade podataka.
Domain/Interfaces/ILinuxMetricsCollector.cs
- Uloga: Interfejs koji definiše ugovor za prikupljanje metrika sa servera (
CollectMetricsAsync). - Zašto radi: Primjenjuje Dependency Inversion Principle (DIP). Aplikacija zavisi od ove apstrakcije, a ne od konkretne implementacije čitača metrika.
Application sloj sadrži biznis logiku, upravljanje konfiguracijom i definicije struktura za prenos podataka.
Application/Options/MetricsOptions.cs
- Uloga: Klasa koja mapira postavke iz
appsettings.json(interval osvježavanja, pragi upozorenja za CPU, režim simulacije). - Zašto radi: Implementira Options Pattern (
IOptions<MetricsOptions>), što omogućava centralizovano upravljanje konfiguracijom.
Application/Dtos/ServerMetricsDto.cs
- Uloga: Data Transfer Object (DTO) koji se šalje klijentima (DataMiner Cube). Sadrži izračunate vrijednosti kao što su procenat iskorištenosti memorije i tekstualni status sistema (OK / WARNING).
- Zašto radi: Pored parametarskog konstruktora, posjeduje i prazan podrazumijevani konstruktor neophodan za
XmlSerializerprilikom generisanja XML odgovora.
Application/Interfaces/IMetricsService.cs
- Uloga: Interfejs koji definiše servisne metode za dobavljanje prerađenih metrika (
GetCurrentMetricsAsync).
Application/Services/MetricsService.cs
- Uloga: Glavni aplikativni servis koji prima sirove podatke od
ILinuxMetricsCollector, preračunava procente i primjenjuje poslovna pravila izMetricsOptions. - Zašto radi: Odvaja čitanje sirovih podataka od njihove interpretacije. Ako je CPU iznad definisanog praga, postavlja status na "WARNING".
Infrastructure sloj sadrži konkretne tehnološke implementacije za čitanje sistemskih fajlova i provjeru zdravlja aplikacije.
Infrastructure/Collectors/RealLinuxMetricsCollector.cs
- Uloga: Implementacija
ILinuxMetricsCollectorinterfejsa koja čita stvarne podatke o RAM-u i CPU-u direktno sa Linux operativnog sistema. - Kako radi:
- Prvo provjerava da li postoji
/host/proc(ako se aplikacija izvršava unutar Docker kontejnera sa mapiranim volumenom) ili klasični/proc. - RAM memoriju čita iz virtuelnog fajla
/proc/meminfo(parsiranjemMemTotaliMemAvailable). - CPU procenat računa iz
/proc/statmjerenjem razlike uidleitotalvremenima u razmaku od 100 milisekundi. - Ukoliko se aplikacija pokrene na okruženju koje nema
/procfajlove, automatski se aktivira sigurni fallback mehanizam kako aplikacija ne bi pukla.
- Prvo provjerava da li postoji
Infrastructure/Health/ServerHealthCheck.cs
- Uloga: Implementacija standardnog .NET
IHealthCheckinterfejsa. - Kako radi: Prilikom poziva
/healthendpointa, dobavlja trenutne metrike. Ako je CPU iznad 95%, vraća statusUnhealthy, ako je iznad 80%, vraćaDegraded, u suprotnom vraćaHealthy.
appsettings.json
- Sadrži postavke za Serilog strukturirano logovanje i prage upozorenja u
MetricsOptionssekciji.
Program.cs
- Uloga: Composition Root aplikacije.
- Kako radi:
- Inicijalizuje Serilog loger koji piše strukturirane logove u konzolu.
- Registruje
MetricsOptions,RealLinuxMetricsCollector,MetricsServicei Health Checks u Dependency Injection kontejner. - Izlaže tri ključna endpointa:
GET /api/metrics- Vraća JSON format.GET /api/metrics/xml- Vraća XML format namijenjen DataMineru.GET /health- Vraća status zdravlja servisa.
U terminalu unutar projekta izvršiti komandu:
dotnet runAplikacija će se pokrenuti na:
- Lokalno:
http://localhost:5051 - Javna domena:
https://dataminercubepocsimulation.onrender.com
curl -s http://localhost:5051/api/metrics
# ili putem javne domene:
curl -s https://dataminercubepocsimulation.onrender.com/api/metricsOčekivani izlaz (JSON):
{
"cpuUsagePercentage": 22.5,
"totalMemoryMb": 11704,
"usedMemoryMb": 9790,
"memoryUsagePercentage": 83.65,
"diskUsagePercentage": 44.38,
"systemStatus": "OK",
"timestampUtc": "2026-07-27T18:44:45.6720596Z"
}curl -s http://localhost:5051/api/metrics/xml
# ili putem javne domene:
curl -s https://dataminercubepocsimulation.onrender.com/api/metrics/xmlOčekivani izlaz (XML):
<?xml version="1.0" encoding="utf-16"?>
<ServerMetricsDto xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CpuUsagePercentage>22.5</CpuUsagePercentage>
<TotalMemoryMb>11704</TotalMemoryMb>
<UsedMemoryMb>9790</UsedMemoryMb>
<MemoryUsagePercentage>83.65</MemoryUsagePercentage>
<DiskUsagePercentage>44.38</DiskUsagePercentage>
<SystemStatus>OK</SystemStatus>
<TimestampUtc>2026-07-27T18:45:06.9927976Z</TimestampUtc>
</ServerMetricsDto>curl -s http://localhost:5051/health
# ili putem javne domene:
curl -s https://dataminercubepocsimulation.onrender.com/healthOčekivani izlaz: Healthy
Da bi se ovaj Web API povezao sa Skyline DataMiner Cube platformom, potrebno je u DataMineru napraviti odgovarajući protokol (konektor).
U DataMiner Studio-u kreira se novi Protocol XML fajl. Ispod je kompletan protokol koji treba da se iskoristi:
<?xml version="1.0" encoding="utf-8"?>
<Protocol xmlns="http://www.skyline.be/config/protocol">
<Name>MirzaHodzicServerMonitoring</Name>
<Version>1.0.8.2</Version>
<Description>FINAL verzija nakon 50 mini verzija, dva dana patnje hahah</Description>
<Vendor>Mirza Hodzic</Vendor>
<ElementType>Http</ElementType>
<Type options="https">http</Type>
<Provider>Mirza Hodzic</Provider>
<Compliancies>
<MinimumRequiredVersion>9.0.0.0</MinimumRequiredVersion>
</Compliancies>
<Display pageOrder="Performance" defaultPage="Performance"/>
<Params>
<Param id="10">
<Name>HttpStatusCode</Name>
<Type>read</Type>
<Interprete>
<RawType>other</RawType>
<LengthType>next param</LengthType>
<Type>string</Type>
</Interprete>
<Display><RTDisplay>false</RTDisplay></Display>
<Measurement><Type>string</Type></Measurement>
</Param>
<Param id="99">
<Name>ResponseStatusCode</Name>
<Description>HTTP Status Kod</Description>
<Type>read</Type>
<Interprete>
<RawType>other</RawType>
<LengthType>next param</LengthType>
<Type>string</Type>
<DefaultValue>200 OK</DefaultValue>
</Interprete>
<Display>
<RTDisplay>true</RTDisplay>
<Positions><Position><Page>Performance</Page><Row>7</Row><Column>0</Column></Position></Positions>
</Display>
<Measurement><Type>string</Type></Measurement>
</Param>
<Param id="101" trending="true">
<Name>CpuUsagePercentage</Name>
<Description>CPU opterećenje servera</Description>
<Type>read</Type>
<Interprete>
<RawType>other</RawType>
<LengthType>next param</LengthType>
<Type>string</Type>
<DefaultValue>0</DefaultValue>
</Interprete>
<Display>
<RTDisplay>true</RTDisplay>
<Units>%</Units>
<Positions><Position><Page>Performance</Page><Row>0</Row><Column>0</Column></Position></Positions>
</Display>
<Measurement><Type>string</Type></Measurement>
<Alarm><Monitored>true</Monitored><WaH>70</WaH><MaH>85</MaH><CH>95</CH></Alarm>
</Param>
<Param id="102" trending="true">
<Name>MemoryUsagePercentage</Name>
<Description>Iskorištenost RAM-a (%)</Description>
<Type>read</Type>
<Interprete>
<RawType>other</RawType>
<LengthType>next param</LengthType>
<Type>string</Type>
<DefaultValue>0</DefaultValue>
</Interprete>
<Display>
<RTDisplay>true</RTDisplay>
<Units>%</Units>
<Positions><Position><Page>Performance</Page><Row>1</Row><Column>0</Column></Position></Positions>
</Display>
<Measurement><Type>string</Type></Measurement>
<Alarm><Monitored>true</Monitored><WaH>80</WaH><MaH>90</MaH><CH>95</CH></Alarm>
</Param>
<Param id="103">
<Name>SystemStatus</Name>
<Description>Status servera</Description>
<Type>read</Type>
<Interprete>
<RawType>other</RawType>
<LengthType>next param</LengthType>
<Type>string</Type>
<DefaultValue>OK</DefaultValue>
</Interprete>
<Display>
<RTDisplay>true</RTDisplay>
<Positions><Position><Page>Performance</Page><Row>2</Row><Column>0</Column></Position></Positions>
</Display>
<Measurement><Type>string</Type></Measurement>
<Alarm>
<Monitored>true</Monitored>
<Possible>
<Value value="WARNING" severity="minor">Upozorenje</Value>
<Value value="CRITICAL" severity="critical">Kritično</Value>
</Possible>
</Alarm>
</Param>
<Param id="104">
<Name>TotalMemoryMb</Name>
<Description>Ukupno RAM (MB)</Description>
<Type>read</Type>
<Interprete>
<RawType>other</RawType>
<LengthType>next param</LengthType>
<Type>string</Type>
<DefaultValue>0</DefaultValue>
</Interprete>
<Display>
<RTDisplay>true</RTDisplay>
<Units>MB</Units>
<Positions><Position><Page>Performance</Page><Row>3</Row><Column>0</Column></Position></Positions>
</Display>
<Measurement><Type>string</Type></Measurement>
</Param>
<Param id="105">
<Name>UsedMemoryMb</Name>
<Description>Iskorišteno RAM (MB)</Description>
<Type>read</Type>
<Interprete>
<RawType>other</RawType>
<LengthType>next param</LengthType>
<Type>string</Type>
<DefaultValue>0</DefaultValue>
</Interprete>
<Display>
<RTDisplay>true</RTDisplay>
<Units>MB</Units>
<Positions><Position><Page>Performance</Page><Row>4</Row><Column>0</Column></Position></Positions>
</Display>
<Measurement><Type>string</Type></Measurement>
</Param>
<Param id="106" trending="true">
<Name>DiskUsagePercentage</Name>
<Description>Iskorištenost diska (%)</Description>
<Type>read</Type>
<Interprete>
<RawType>other</RawType>
<LengthType>next param</LengthType>
<Type>string</Type>
<DefaultValue>0</DefaultValue>
</Interprete>
<Display>
<RTDisplay>true</RTDisplay>
<Units>%</Units>
<Positions><Position><Page>Performance</Page><Row>5</Row><Column>0</Column></Position></Positions>
</Display>
<Measurement><Type>string</Type></Measurement>
</Param>
<Param id="107">
<Name>TimestampUtc</Name>
<Description>Vrijeme očitavanja (UTC)</Description>
<Type>read</Type>
<Interprete>
<RawType>other</RawType>
<LengthType>next param</LengthType>
<Type>string</Type>
</Interprete>
<Display>
<RTDisplay>true</RTDisplay>
<Positions><Position><Page>Performance</Page><Row>6</Row><Column>0</Column></Position></Positions>
</Display>
<Measurement><Type>string</Type></Measurement>
</Param>
<Param id="1000">
<Name>RawXmlResponse</Name>
<Type>read</Type>
<Interprete>
<RawType>other</RawType>
<LengthType>next param</LengthType>
<Type>string</Type>
</Interprete>
<Display>
<RTDisplay>true</RTDisplay>
<Positions><Position><Page>Performance</Page><Row>8</Row><Column>0</Column></Position></Positions>
</Display>
<Measurement><Type>string</Type></Measurement>
</Param>
</Params>
<QActions>
<QAction id="1" name="ParseXmlResponse" encoding="csharp" triggers="1000">
<![CDATA[
using System;
using System.Xml;
using Skyline.DataMiner.Scripting;
public class QAction
{
public static void Run(SLProtocol protocol)
{
try
{
string xml = Convert.ToString(protocol.GetParameter(1000));
if (string.IsNullOrEmpty(xml)) return;
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
protocol.SetParameter(101, GetTagValue(doc, "CpuUsagePercentage"));
protocol.SetParameter(102, GetTagValue(doc, "MemoryUsagePercentage"));
protocol.SetParameter(103, GetTagValue(doc, "SystemStatus"));
protocol.SetParameter(104, GetTagValue(doc, "TotalMemoryMb"));
protocol.SetParameter(105, GetTagValue(doc, "UsedMemoryMb"));
protocol.SetParameter(106, GetTagValue(doc, "DiskUsagePercentage"));
protocol.SetParameter(107, GetTagValue(doc, "TimestampUtc"));
protocol.SetParameter(99, "200 OK");
}
catch (Exception ex)
{
protocol.Log("QA1 Error: " + ex.Message, LogType.Error, LogLevel.NoLogging);
}
}
private static string GetTagValue(XmlDocument doc, string tag)
{
XmlNodeList nodes = doc.GetElementsByTagName(tag);
return nodes.Count > 0 ? nodes[0].InnerText : "";
}
}
]]>
</QAction>
</QActions>
<HTTP>
<Session id="1" name="GetServerMetrics">
<Connection id="1">
<Request verb="GET" url="/api/metrics/xml"/>
<Response statusCode="10">
<Content pid="1000"/>
</Response>
</Connection>
</Session>
</HTTP>
<Groups>
<Group id="1">
<Name>GetServerMetricsGroup</Name>
<Type>poll</Type>
<Content>
<Session>1</Session>
</Content>
</Group>
</Groups>
<Timers>
<Timer id="1" On="startup">
<Name>5-Second Polling Timer</Name>
<Time>5000</Time>
<Interval>5000</Interval>
<Content>
<Group>1</Group>
</Content>
</Timer>
</Timers>
</Protocol>Osnovne informacije:
- Name:
MirzaHodzicServerMonitoring- identifikator protokola - Version:
1.0.1.0- verzija protokola - ElementType:
Http- tip elementa koji će se kreirati - Display: Prikazuje samo jednu stranicu "Performance" sa svim parametrima
Parametri (Params):
- PID 101 (CPU): Prikazuje CPU opterećenje sa alarmima na 70% (upozorenje), 85% (ozbiljno) i 95% (kritično)
- PID 102 (RAM): Prikazuje iskorištenost RAM-a sa alarmima na 80%, 90% i 95%
- PID 103 (Status): Tekstualni status sistema sa mogućim vrijednostima OK, WARNING, CRITICAL
- PID 104 (Total RAM): Ukupna količina RAM-a u MB
- PID 105 (Used RAM): Iskorištena količina RAM-a u MB
- PID 106 (Disk): Iskorištenost diska u procentima
- PID 107 (Timestamp): Vrijeme očitavanja u UTC formatu
Poling (Polling):
- Timer svakih 5 sekundi (5000ms) pokreće HTTP zahtjev
- HTTP GET zahtjev se šalje na
/api/metrics/xml - XML odgovor se parsira pomoću XPath izraza
- Svaki parametar dobija vrijednost iz odgovarajućeg XML elementa
- Otvoriti DataMiner Cube interfejs.
- Kliknuti na "Add Element" ili koristiti CTRL+N.
- U polje "Protocol" pretražiti i odabrati "MirzaHodzicServerMonitoring".
- Za "Name" unijeti naziv elementa (npr. "Linux Server Monitor").
- Za "Address" bus veze unijeti jednu od sljedećih adresa:
- Lokalno:
http://localhost:5051 - Javna domena:
https://dataminercubepocsimulation.onrender.com
- Lokalno:
- Kliknuti "Create".
- Element će se pojaviti u listi elemenata i automatski početi prikupljati podatke.
- Dvostrukim klikom na element otvara se prozor sa svim metrikama na "Performance" stranici.
- AUTOMATSKO ODRŽAVANJE AKTIVNOSTI (Render Keep-Alive): Kako je backend besplatni Render servis koji se inače uspavljuje nakon 15 minuta neaktivnosti, u repozitoriju je podešen automatski GitHub Actions workflow (
.github/workflows/keep_alive.yml) koji svakih 10 minuta šalje ping nahttps://dataminercubepocsimulation.onrender.com/api/metrics/xmli drži server stalno budnim 24/7.
name: Render Backend Keep-Alive
on:
schedule:
# Runs every 10 minutes to prevent Render free instance from spinning down
- cron: '*/10 * * * *'
workflow_dispatch:
jobs:
ping:
runs-on: ubuntu-latest
steps:
- name: Ping Render Backend Health Endpoint
run: |
curl -s -o /dev/null -w "%{http_code}" https://dataminercubepocsimulation.onrender.com/api/metrics/xmlNakon kreiranja elementa, DataMiner Cube će automatski:
- Prikazivati sve metrike u realnom vremenu na "Performance" tabu
- Generisati trendove (grafikone) za PID-ove sa
trending="true"(CPU, RAM, Disk) - Aktivirati alarme kada vrijednosti pređu definisane pragove
- Omogućiti kreiranje dashboarda sa prilagođenim prikazima
Za dodatne informacije, pitanja ili podršku, kontaktirajte autora putem GitHub repozitorija.
