Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Womit Daten loggen für Geräteserver
#CPferdchen
myCSharp.de - Member



Dabei seit:
Beiträge: 28

Themenstarter:

Womit Daten loggen für Geräteserver

beantworten | zitieren | melden

Hallo,

im Rahmen meiner Masterarbeit arbeite ich zur Zeit an einem Geräteserver. Der Server holt sich Werte von verschiedenen Geräten wie SPS, Leistungsmessgerät, Sensoren usw. die über verschiedene Arten und Schnittstellen angebunden sind. Zum Beispiel USB, CAN, Flexray, TCP/IP.
Zum Server gehört ein Clients der definiert welche Werte von welchen Geräten er haben möchte und teilt dies dem Server mit. Der Server startet und verwaltet die GEräte und stellt dem Client die Werte zur Verfügung. Entweder direkt (eingebunden als DLL in Client App) oder über TCP/IP.
Die Datenrate mit der die Werte aus den Geräte gelesen und übertragen werden soll liegt bei einigen bei 1 oder 5 m/s meist eher 10m/s , der Datentype sollte i.d.R. ein primitiver Typ sein.

Nun möchte ich in meiner Server-Applikation ein Datenlogging/DataHistory anlegen. Dazu habe ich eine sycronisierte Queue angelegt in die Wert, Zeitpunkt und Geräte(Herkunft/Id abgelegt werden können. Nun würde ich mir einen Task anlegen der diese Queue ausließt und alles was darin ist persistent abspeichert.

Meine Anforderung:
- wenig Performance fressend (um Datenraten einzuhalten)
- große Datenmengen (Laufzeit des Servers über Monate)
- alte Daten leicht löschbar (nur Werte der letzen x-Stunden/Tage)
- leicht umgänglichen Datensystem (ungeschulte Person soll sich die Daten anschauen können und eventuell auch damit Arbeiten)
- aufgetrenntes Speichern der Werte für verschiedene Geräte

Meine bisherigen Ideen sind:
- SQLite (Erlaubt performante Transactions, gute Auftrennung(Tables),schon mit gearbeitet, für größere Datenmengen, gute Wartbarkait ,umgäglichkeit nur bedingt mit SQLite Browser (Installation notwendig))
- mehrere asyncron beschriebene .data / .txt Dateien für jedes Gerät (sehr nativ,schon mit gearbeitet, schlecht wartbar auch wenn z.B. alle Stunde eine neue Datei angelgt wird, nicht so super für große Datenmengen, txt kann jeder öffnen )
- Common Logging .Net API (gar keine Erfahrung, überhaupt sinnvoll?, Elefanten/Spatzen schießen)
- XML (nativ, Auftrennung in einer Datei möglich, einigermassen umgänglich, Wartbarkeit auch ok)

Nun bin ich mir unsicher was ich nutzen sollte. Vorallem was die Performance angeht. Um den Punkt Umgänglichkeit zum umschiffen hab ich auch schon überlegt die Funktion einbaue aus den gespeicherten Werten eine Excel-Datei zu genieren. Am meisten bin ich von SQLite angetan, aber mein Betreuer aus oben genannten Gründen nicht

Habt ihr noch andere Ideen? Oder Argumente pro SQLite?

Viele Grüße
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 6.779
Herkunft: Waidring

beantworten | zitieren | melden

Hallo #CPferdchen,

wenn du eh am Server arbeitest, so kannst du dort eine richtige Datenbank verwenden. Z.B. SQL Server und dort die Daten hinschreiben.

Für die Verwaltung der Werte bzw. Umgänglichkeit erstellt du eine (einfache) Web-Anwendung und somit kann auch ein ungeschulter Benutzer die Daten manipulieren (entsprechende Rechte können vorausgesetzt werden in der Anwendung).

Über Reporting Services, usw. könnten dann auch gleich Diagramme, Berichte erstellt werden.
Zitat
sycronisierte Queue angelegt in die Wert, Zeitpunkt und Geräte(Herkunft/Id abgelegt werden können. Nun würde ich mir einen Task anlegen der diese Queue ausließt und alles was darin ist persistent abspeichert.
Ob ein Task reicht od. nicht hängt von der Anwendung ab.
Alternativ kannst du auch einen Logging-Dienst erstellen und dein Programm kommuniziert mit diesem Dienst per WCF (ev. mit MessageQueue-Binding). Deine Anwendung stellt die Daten in diese "Qeueu" und der Dienst liest die Daten sicher aus und speichert diese in der Datenbank.
Ev. ist dies aber schon zuviel des Guten und ein Task reicht auch. Das musst du entscheiden.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
private Nachricht | Beiträge des Benutzers
weismat
myCSharp.de - Member



Dabei seit:
Beiträge: 872
Herkunft: Frankfurt am Main

beantworten | zitieren | melden

Ich würde Dir an Deiner Stelle Event Tracing empfehlen.
Es ist etwas komplexer als normales Logging, dafür rasend schnell - so wird es in der CLR für die Garbage Collector Statistiken benutzt.
Ich habe selber etwas dazu auf meinem Blog - Windows Event Tracing in C# - vor kurzem geschrieben.

Edit: Mit Perfview kannst Du in Excel exportieren - wichtig ist auch, daß das Sammeln und das Auswerten getrennt sind. Es gibt auch andere Tools zum Sammeln, die zum Beispiel anhand der Dateigröße rollen. Es gibt viele Möglichkeiten, aber das ganze ist nicht so einfach.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von weismat am .
private Nachricht | Beiträge des Benutzers
#CPferdchen
myCSharp.de - Member



Dabei seit:
Beiträge: 28

Themenstarter:

beantworten | zitieren | melden

Hallo,

Vielen Dank für eure Antworten.
Zitat von gfoidl
wenn du eh am Server arbeitest, so kannst du dort eine richtige Datenbank verwenden. Z.B. SQL Server und dort die Daten hinschreiben.
Würde aber heißen, dass immer wenn ich ein neues System mit dem Geräteserver aufsetze ich auch einen SQL Server mit aufsetzen muss. Ein zentraler SQL Server in unserem Unternehmen wäre hier die Lösung, aber der Geräteserver soll auch isoliert vom Netz funktionieren.
Zitat von gfoidl
Alternativ kannst du auch einen Logging-Dienst erstellen und dein Programm kommuniziert mit diesem Dienst
Das ganze als Dienst laufen zu lassen ist eine super Idee. Kannte ich als eigene Anwedung in C# bis her nicht. Wenn ich mir dieses Tutotial Windows Services mit C#so anschaue wäre das vielleicht auch was für meine TCP Client/Server Kommunikation.
Zitat von gfoidl
Ob ein Task reicht od. nicht hängt von der Anwendung ab.
Wie meinst du das? Die Anzahl der Task oder ob ich einen Dienst verwende?

Zitat von weismat
Ich würde Dir an Deiner Stelle Event Tracing empfehlen.
Es ist etwas komplexer als normales Logging, dafür rasend schnell - so wird es in der CLR für die Garbage Collector Statistiken benutzt.
Ich habe selber etwas dazu auf meinem Blog vor kurzem geschrieben.
Rasend schnell hört sich gut an :D. Werde mal versuchen dazu eine Test Applikation zu schreiben. Hast du noch weitere nützliche Links zu dem Thema?

Ich habe gestern dieses mit SQLite gebastelt, aber euere Lösungen hören sich schneller und professioneller an.


using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Threading;
using System.Threading.Tasks;
using VB.Core.Channel;


//TODO: Erkennen und separieren der Channel auf einzelne Tables
//TODO: Eigene Spalten in den Tables statt einen String
//TODO: gescheiten Zeitstempel anlegen

namespace VB.Server
{
  public class Data
  {
    public Data (ChannelAddress channelAddress, Type channelType, object value)
    {
      ChannelAddress = channelAddress;
      ChannelType = channelType;
      Value = value;
    }

    public ChannelAddress ChannelAddress { get; set; }
    public Type ChannelType { get; set; }
    public object Value { get; set; }

    public override string ToString ()
    {
      return string.Format ("{0} | {1} | {2}", ChannelAddress, ChannelType, Value);
    }
  }

  public static class DataHistory
  {
    public static Queue SynchronizedQueue = Queue.Synchronized (new Queue (new Queue<Data> ()));
    private static readonly object _lockObject = new object ();

    public static void syncEnqueue (ChannelAddress channelAddress, Type channelType, object value)
    {
      lock (_lockObject)
      {
        SynchronizedQueue.Enqueue (new Data (channelAddress, channelType, value));
      }
    }

    public static string syncDequeue ()
    {
      lock (_lockObject)
      {
        return  (SynchronizedQueue.Dequeue ()).ToString ();
      }
    }
  }

  public class DataHistoryTask
  {
    private bool _shouldStop;
    private const int TransactionLimit = 100;

    public void Start ()
    {
      new Task (
        () =>
        {
          
          SQLiteConnection.CreateFile ("sqliteTest.db");
          SQLiteConnection sqLiteConnection = new SQLiteConnection ();
          sqLiteConnection.ConnectionString = "Data Source = sqliteTest.db; Version=3";
          sqLiteConnection.Open ();

          SQLiteCommand sqLiteCommand = new SQLiteCommand (sqLiteConnection);
          sqLiteCommand.CommandText = "CREATE TABLE IF NOT EXISTS Test (tick INTEGER NOT NULL, str VARCHAR(200) NOT NULL)";
          sqLiteCommand.ExecuteNonQuery ();

          while (_shouldStop != true)
          {
            Thread.Sleep (1000);

            if (DataHistory.SynchronizedQueue.Count < 1000)
            {
              continue;
            }

            using (var sqLiteTransaction = sqLiteConnection.BeginTransaction ())
            {
              sqLiteCommand.Connection = sqLiteConnection;
              sqLiteCommand.Transaction = sqLiteTransaction;
              int transactionCounter = 0;

              while( DataHistory.SynchronizedQueue.Count > 0 && transactionCounter < TransactionLimit)
              {          
                sqLiteCommand.CommandText = "INSERT INTO Test (tick, str) VALUES(1,'" + DataHistory.syncDequeue () + "')";
                sqLiteCommand.ExecuteNonQuery ();
                transactionCounter++;
              }
              sqLiteTransaction.Commit ();
              Thread.Sleep (1);
            }
          }
          sqLiteConnection.Close ();
        }).Start ();
    }

    public void Stop ()
    {
      _shouldStop = true;
    }
  }
}

EDIT:

 if (DataHistory.SynchronizedQueue.Count < 1000)
            {
              continue;
            }
und

  while( DataHistory.SynchronizedQueue.Count > 0 && transactionCounter < TransactionLimit)
muss ich nochmal abändern :P

LG
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von #CPferdchen am .
private Nachricht | Beiträge des Benutzers
weismat
myCSharp.de - Member



Dabei seit:
Beiträge: 872
Herkunft: Frankfurt am Main

beantworten | zitieren | melden

Schau Dir die Channel 9 Videos und diese Übersicht an.
Ich habe noch mehr Material als Powerpoint.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von weismat am .
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 6.779
Herkunft: Waidring

beantworten | zitieren | melden

Hallo #CPferdchen,
Zitat
Wie meinst du das? Die Anzahl der Task oder ob ich einen Dienst verwende?
Ich meine das so, dass es darauf ankommt wie sehr du das Logging von der Anwendung entkoppeln willst. Mit dem separaten Dienst ist das Logging in einen eigenen Prozess - den Dienst-Prozess - ausgelagert mit allen Vor- und Nachteilen.
Wird mittels Task geloggt, so ist das Logging im selben Prozess. Wobei Logging duch Task wohl am ehesten per Producer/Consumer (siehe z.B. auch Sinnvoller Einsatz des Producer Consumer Patterns) umgesetzt wird.

Was für deine Anwendung und Anforderung besser passend ist, kann ich nicht beurteilen - das obliegt dir.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
private Nachricht | Beiträge des Benutzers
Palin
myCSharp.de - Member



Dabei seit:
Beiträge: 1.090

beantworten | zitieren | melden

Hast du mal geschaut ob eine der Standard Logger, deiner Anforderungen erfüllen.

Log4Net, z.B. bietet die Möglichkeit in Dateien, Datenbanken oder als Mail zu loggen.
(Den Verwenden ich z.B. und falls doch mal was anderes Verlangt wird, habe ich einen Wrapper um den Logger und die Faktory geschrieben (grob 10 Zeilen Code))
Sollte man mal gelesen haben:

Clean Code Developer
Entwurfsmuster
Anti-Pattern
private Nachricht | Beiträge des Benutzers