Table of Contents

SQL Ausgabe-Plugin

Das SQL-Ausgabe-Plugin schreibt log4TC-Meldungen in eine relationale Datenbank. Log4TC unterstützt derzeit vier Datenbanken: MySql/MariaDB, PostgreSql und MS SQLServer.

Vorbreitung der Datenbank

Um Meldungen an eine SQL-Datenbank ausgeben zu können muss das Schema zuerst in der Datenbank vorbereitet werden. Log4TC unterstützt momentan zwei Varianten. Die DDL's zu den jeweiligen Datenbanken befinden sich am Ende dieses Artikels.

Konfiguration in log4TC

Die Konfiguration für den log4TC-Service (%ProgramData%\log4TC\config\appsettings.json) sieht wie folgt aus:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "Outputs": [
    {
      "Type": "sql",
      "Config": {
        "Driver": "MySql, Postgres oder SqlServer",
        "ConnectionString": "siehe Text",
        "Scheme": "SimpleFlat oder FullFlat"
      }
    }
  ]
}

Driver

Definiert den Treiber für den Zugriff auf die Datenbank. Momentan wird log4TC mit Treibern für folgende Datenbank ausgeliefert:

ConnectionString

Legt die Verbindungseinstellungen zu der ausgewählten Datenbank fest. Der String ist Abhängig von der Datenbank. Die Webseite https://www.connectionstrings.com/ liefert eine gute Übersicht über weitergehende Parameter.

  • MySql/MariaDB: Server=dbserverhost;Port=3306;Database=databasename;Uid=user;Pwd=password;
  • Postgres: User ID=user;Password=password;Host=dbserverhost;Port=5432;Database=databasename;Pooling=true;
  • SqlServer: Server=dbserverhost,1433;Database=dbserverhost;User Id=user;Password=password;

Scheme

Legt fest, in welchen Format die log4TC-Meldungen geschrieben werden sollen. Momentan werden zwei Varianten unterstützt:

  • SimpleFlat - Einfaches Schema mit einer Tabelle; strukturierte Daten werden nicht geschrieben (nur im Message-Text)
  • FullFlat - Schreibt die Context- und Argument-Strukturen für jede Meldung in separate Tabellen

log4TC SQL-Schema

Note

Benötigen Sie ein anderes Schema oder eine andere Datenbank? Kontaktieren Sie uns!

SimpleFlat

Dies ist das einfachste Format und entspricht in etwas den Informationsgehalt von Log-Files.

Tabelle log_entry:

Spalte Bedeutung
id Eindeutige ID (Primary-Key), wird von der Datenbank vergeben
source Die Ads-Net-Id von der die Log-Message empfangen wurde.
hostname Der Hostname von dem die Log-Message empfangen wurde.
formatted_message Die formatierte Meldung, die in der SPS geschrieben wurde.
logger Der Loggername der Log-Meldung.
level Der Log-Level der Log-Meldung.
plc_timestamp Der (interne) PLC-Zeitstempel der TwinCAT-Runtime, wenn die Meldung erzeugt wurde.
clock_timestamp Der Zeitstempel der Windowsuhr (geringe Genaugikeit)
task_index Der TwinCAT Task-Index (1-x)
task_name Der Name der TwinCAT Application
task_cycle_counter Der Wert des Task-Zykluszähler (alle Meldungen vom gleichen Zyklus haben den gleichen Wert)
app_name Der Name der TwinCAT Application (z.B. Port_851)
project_name Der Name des SPS-Projekts.
onlinechange_count Anzahl der Online-Changes

FullFlat

Dieses Format enthält alle log4TC-Daten inkl. Argumente und Context in einem flachen Format. Dieses Schema besteht aus drei Tabellen:

Tabelle log_entry:

Spalte Bedeutung
id Eindeutige ID (Primary-Key), wird von der Datenbank vergeben
source Die Ads-Net-Id von der die Log-Message empfangen wurde.
hostname Der Hostname von dem die Log-Message empfangen wurde.
formatted_message Die formatierte Meldung, die in der SPS geschrieben wurde.
message Die rohe Meldung mit Platzhaltern, so wie sie in der SPS geschrieben wurde.
logger Der Loggername der Log-Meldung.
level Der Log-Level der Log-Meldung.
plc_timestamp Der (interne) PLC-Zeitstempel der TwinCAT-Runtime, wenn die Meldung erzeugt wurde.
clock_timestamp Der Zeitstempel der Windowsuhr (geringe Genaugikeit)
task_index Der TwinCAT Task-Index (1-x)
task_name Der Name der TwinCAT Application
task_cycle_counter Der Wert des Task-Zykluszähler (alle Meldungen vom gleichen Zyklus haben den gleichen Wert)
app_name Der Name der TwinCAT Application (z.B. Port_851)
project_name Der Name des SPS-Projekts.
onlinechange_count Anzahl der Online-Changes

Tabelle log_argument:

Spalte Bedeutung
id Eindeutige ID (Primary-Key), wird von der Datenbank vergeben
log_entry_id Referenz die Tabelle log_entry
idx Der Argument-Index in der zugehörigen Log-Message
value Der Argument-Wert als String
type Der Usprungstyp des Arguments

Tabelle log_context:

Spalte Bedeutung
id Eindeutige ID (Primary-Key), wird von der Datenbank vergeben
log_entry_id Referenz die Tabelle log_entry
name Der Context-Name der zugehörigen Log-Message
value Der Context-Wert als String
type Der Usprungstyp des Context-Attributts

Anhang: DDL für Datenbank-Schemas

MySql/MariaDB

SimpleFlat

CREATE TABLE IF NOT EXISTS log_entry (
    id                 BIGINT AUTO_INCREMENT PRIMARY KEY,
    source             VARCHAR(30) NOT NULL,
    hostname           VARCHAR(30) NOT NULL,
    formatted_message  TINYTEXT NOT NULL,
    logger             VARCHAR(255) NOT NULL,
    level              ENUM('trace', 'debug', 'info', 'warn', 'error', 'fatal') NOT NULL,
    plc_timestamp      TIMESTAMP NOT NULL,
    clock_timestamp    TIMESTAMP NULL,
    task_index         TINYINT NOT NULL,
    task_name          VARCHAR(63) NOT NULL,
    task_cycle_counter INT NOT NULL,
    app_name           VARCHAR(63) NOT NULL,
    project_name       VARCHAR(63) NOT NULL,
    onlinechange_count INT NOT NULL
);

FullFlat

CREATE TABLE IF NOT EXISTS log_entry (
    id                 BIGINT AUTO_INCREMENT PRIMARY KEY,
    source             VARCHAR(30) NOT NULL,
    hostname           VARCHAR(30) NOT NULL,
    formatted_message  TINYTEXT NOT NULL,
    message            TINYTEXT NOT NULL,
    logger             VARCHAR(255) NOT NULL,
    level              ENUM('trace', 'debug', 'info', 'warn', 'error', 'fatal') NOT NULL,
    plc_timestamp      TIMESTAMP NOT NULL,
    clock_timestamp    TIMESTAMP NULL,
    task_index         TINYINT NOT NULL,
    task_name          VARCHAR(63) NOT NULL,
    task_cycle_counter INT NOT NULL,
    app_name           VARCHAR(63) NOT NULL,
    project_name       VARCHAR(63) NOT NULL,
    onlinechange_count INT NOT NULL
);

CREATE TABLE IF NOT EXISTS log_argument (
    Id                  BIGINT AUTO_INCREMENT PRIMARY KEY,
    log_entry_id        BIGINT NOT NULL REFERENCES log_entry(id),
    idx                 TINYINT NOT NULL,
    value               TINYTEXT NOT NULL,
    type                ENUM('null', 'byte', 'word', 'dword', 'real', 'lreal', 'sint', 'int', 'dint', 'usint', 'uint', 'udint', 'string', 'bool', 'ularge', 'large') NOT NULL,
    UNIQUE (log_entry_id, idx)
);

CREATE TABLE IF NOT EXISTS log_context (
    id                  BIGINT AUTO_INCREMENT PRIMARY KEY,
    log_entry_id        BIGINT NOT NULL REFERENCES log_entry(id),
    name                VARCHAR(255) NOT NULL,
    value               TINYTEXT NOT NULL,
    type                ENUM('null', 'byte', 'word', 'dword', 'real', 'lreal', 'sint', 'int', 'dint', 'usint', 'uint', 'udint', 'string', 'bool', 'ularge', 'large') NOT NULL,
    UNIQUE (log_entry_id, name)
);

Postgres

SimpleFlat

CREATE TYPE log_level_type AS ENUM('trace', 'debug', 'info', 'warn', 'error', 'fatal');

CREATE TABLE IF NOT EXISTS log_entry (
    id                 BIGSERIAL PRIMARY KEY,
    source             VARCHAR(30) NOT NULL,
    hostname           VARCHAR(30) NOT NULL,
    formatted_message  TEXT NOT NULL,
    logger             VARCHAR(255) NOT NULL,
    level              log_level_type NOT NULL,
    plc_timestamp      TIMESTAMP NOT NULL,
    clock_timestamp    TIMESTAMP NULL,
    task_index         SMALLINT NOT NULL,
    task_name          VARCHAR(63) NOT NULL,
    task_cycle_counter INT NOT NULL,
    app_name           VARCHAR(63) NOT NULL,
    project_name       VARCHAR(63) NOT NULL,
    onlinechange_count INT NOT NULL
);

FullFlat

CREATE TYPE log_level_type AS ENUM('trace', 'debug', 'info', 'warn', 'error', 'fatal');

CREATE TABLE IF NOT EXISTS log_entry (
    id                 BIGSERIAL PRIMARY KEY,
    source             VARCHAR(30) NOT NULL,
    hostname           VARCHAR(30) NOT NULL,
    formatted_message  TEXT NOT NULL,
    message            TEXT NOT NULL,
    logger             VARCHAR(255) NOT NULL,
    level              log_level_type NOT NULL,
    plc_timestamp      TIMESTAMP NOT NULL,
    clock_timestamp    TIMESTAMP NULL,
    task_index         SMALLINT NOT NULL,
    task_name          VARCHAR(63) NOT NULL,
    task_cycle_counter INT NOT NULL,
    app_name           VARCHAR(63) NOT NULL,
    project_name       VARCHAR(63) NOT NULL,
    onlinechange_count INT NOT NULL
);

CREATE TYPE log_value_type AS ENUM('null', 'byte', 'word', 'dword', 'real', 'lreal', 'sint', 'int', 'dint', 'usint', 'uint', 'udint', 'string', 'bool', 'ularge', 'large');

CREATE TABLE IF NOT EXISTS log_argument (
    id                  SERIAL PRIMARY KEY,
    log_entry_id        BIGINT NOT NULL REFERENCES log_entry(id),
    idx                 SMALLINT NOT NULL,
    value               TEXT NOT NULL,
    type                log_value_type NOT NULL,
    UNIQUE (log_entry_id, idx)
);

CREATE TABLE IF NOT EXISTS log_context (
    id                  SERIAL PRIMARY KEY,
    log_entry_id        BIGINT NOT NULL REFERENCES log_entry(id),
    name                VARCHAR(255) NOT NULL,
    value               TEXT NOT NULL,
    type                log_value_type NOT NULL,
    UNIQUE (log_entry_id, name)
);

SQL-Server

SimpleFlat

CREATE TABLE log_entry (
    id                 INT IDENTITY PRIMARY KEY,
    source             VARCHAR(30) NOT NULL,
    hostname           VARCHAR(30) NOT NULL,
    formatted_message  TEXT NOT NULL,
    logger             VARCHAR(255) NOT NULL,
    level              CHAR(5) NOT NULL,
    plc_timestamp      DATETIME2 NOT NULL,
    clock_timestamp    DATETIME2 NULL,
    task_index         SMALLINT NOT NULL,
    task_name          VARCHAR(63) NOT NULL,
    task_cycle_counter INT NOT NULL,
    app_name           VARCHAR(63) NOT NULL,
    project_name       VARCHAR(63) NOT NULL,
    onlinechange_count INT NOT NULL
);

FullFlat

CREATE TABLE log_entry (
    id                 BIGINT IDENTITY PRIMARY KEY,
    source             VARCHAR(30) NOT NULL,
    hostname           VARCHAR(30) NOT NULL,
    formatted_message  TEXT NOT NULL,
    message            TEXT NOT NULL,
    logger             VARCHAR(255) NOT NULL,
    level              CHAR(5) NOT NULL,
    plc_timestamp      DATETIME2 NOT NULL,
    clock_timestamp    DATETIME2 NULL,
    task_index         SMALLINT NOT NULL,
    task_name          VARCHAR(63) NOT NULL,
    task_cycle_counter INT NOT NULL,
    app_name           VARCHAR(63) NOT NULL,
    project_name       VARCHAR(63) NOT NULL,
    onlinechange_count INT NOT NULL
);

CREATE TABLE log_argument (
    id                  BIGINT IDENTITY PRIMARY KEY,
    log_entry_id        BIGINT NOT NULL,
    idx                 SMALLINT NOT NULL,
    value               TEXT NOT NULL,
    type                CHAR(6) NOT NULL,
    UNIQUE (log_entry_id, idx),
    FOREIGN KEY (log_entry_id) REFERENCES log_entry(id)
);

CREATE TABLE log_context (
    id                  BIGINT IDENTITY PRIMARY KEY,
    log_entry_id        BIGINT NOT NULL,
    name                VARCHAR(255) NOT NULL,
    value               TEXT NOT NULL,
    type                CHAR(6) NOT NULL,
    UNIQUE (log_entry_id, name),
    FOREIGN KEY (log_entry_id) REFERENCES log_entry(id)
);