Versionen im Vergleich

Schlüssel

  • Diese Zeile wurde hinzugefügt.
  • Diese Zeile wurde entfernt.
  • Formatierung wurde geändert.

...

Ab 4.19.0 und 4.18.2: Im Webclient kann der Super-User das Logging während des Betriebs an- und ausschalten, rechts unter dem Zahnrad-Dropdown Menüpunkt "Server Info". Log level für den gewünschten Logger auf "DEBUG" setzen:

Allgemeines zum Logging

Nuclos verwendet intern log4j Version 1.2.x für das Logging. Wenn Sie in Ihrer Installation die Datei <nuclos_home>/conf/log4j.properties anpassen, können Sie das Log Verhalten des Servers in weiten Bereichen konfigurieren. Auf diese Seite finden Sie verschiedene Beispielkonfigurationen, die

  • bestimmte Log Events in eine separate Datei schreiben,
  • bestimmte Log Events statt in einer Datei in der Datenbank loggen und
  • die Ausführlichkeit des Loggings für verschiedene Log Bereiche (z.B. Java Klassen) anpassen.

Weitergehende Informationen zu log4j finden Sie z.B. unter

Info

Die hier vorgestellte Methode, unterschiedliche Log Dateien zu erzeugen und/oder das Logging in eine Datenbank umzuleiten, funktionieren auch in weiteren Fällen. Beispielsweise ist es möglich, das client lifecycle logging auf dem Server entsprechend zu konfigurieren. Das zu konfigurierende Log Handle ist hierbei org.nuclos.server.web.ClientLifecycle.

Separate Log Datei für Client Lifecycle Events

Codeblock
# standard log stuff
log4j.appender.logfile=org.apache.log4j.RollingFileAppender
log4j.appender.logfile.File=/home/tpasch2/nuclos4/logs/server.log
log4j.appender.logfile.MaxBackupIndex=1000
log4j.appender.logfile.MaxFileSize=1GB
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.rootLogger=INFO, stdout, logfile

# create another log file
log4j.appender.clientlifecycle=org.apache.log4j.RollingFileAppender
log4j.appender.clientlifecycle.File=/home/tpasch2/nuclos4/logs/clientlifecycle.log
log4j.appender.clientlifecycle.MaxBackupIndex=1000
log4j.appender.clientlifecycle.MaxFileSize=1GB
log4j.appender.clientlifecycle.layout=org.apache.log4j.PatternLayout
log4j.appender.clientlifecycle.layout.ConversionPattern=%d %p [%c] - %m%n

# use the file for a certain category
log4j.category.org.nuclos.server.web.ClientLifecycle=INFO, clientlifecycle
log4j.additivty.org.nuclos.server.web.ClientLifecycle=false
log4j.logger.org.nuclos.server.web.ClientLifecycle=INFO

Standard SQL Logging

Um alle SQL Statements zu loggen, müssen folgende Zeilen in der log4j.properties hinzugefügt werden:

Codeblock
titlelog4j
#SQL logging
log4j.logger.SQLLogger=DEBUG

Für log4j2 sieht die Konfiguration der log4j2.xml aus wie folgt:

Codeblock
titlelog4j2 - Ausgabe des SQL-Logging im Server-Log
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d %p [%c] - %m%n"/>
    </Console>
    <RollingFile name="Logfile" fileName="<Nuclos-Log-Verzeichnis>/server.log"
                filePattern="<Nuclos-Log-Verzeichnis>/server-%i.log" 
                append="true">
      <PatternLayout pattern="%d %p [%c] - %m%n"/>
      <Policies>
        <SizeBasedTriggeringPolicy size="5 MB"/>
                </Policies>
          <DefaultRolloverStrategy max="20"/>
    </RollingFile>
  </Appenders>
  <Loggers>
    <Logger name="org.apache.log4j.xml" level="info"/>
    <Logger name="SQLLogger" level="debug"/> 
	<Root level="info">
      <AppenderRef ref="Console"/>
      <AppenderRef ref="Logfile"/>
    </Root>
  </Loggers>
</Configuration>

SQL Timer per REST einschalten:

 

Codeblock
curl --cookie-jar cookies.txt http://localhost:8080/nuclos-war/rest -X POST -H "Content-Type: application/json" -d '{"username":"'nuclos'", "password":"''"}';
curl --cookie cookies.txt http://localhost:8080/nuclos-war/rest/maintenance/logging/SQLTimer/level -X PUT -H "Content-Type: application/json" -d '{"level":"'debug'"}';

 

bzw. reines SQL Logging vor der Ausführung ohne Timer mit "SQLLogger" statt "SQLTimer" bzw. mit "SQLUpdate" für das ausschließliche Loggen von "UDPATE/INSERT/DELETE"-Statements. Zum Abschalten des Logging den Level wieder von "debug" auf "info" setzen.

Standard SQL Logging

Um alle SQL Statements zu loggen: So sieht die Konfiguration der log4j2.xml aus, wenn einfache SQLLogging (vor dem Ausführen des SQL Statements) eingeschalten werden sollDas SQL-Logging lässt sich auch in einem eigenen Log-File ausgeben. Dafür müsste dann ein eigener Appender definiert, und im SQL-Logger referenziert werden:

Codeblock
titlelog4j2 - Ausgabe des SQL-Logging in einem eigenen Log-Fileim Server-Log
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d %p [%c] - %m%n"/>
    </Console>
    <RollingFile name="Logfile" fileName="<Nuclos-Log-Verzeichnis>/server.log"
                filePattern="<Nuclos-Log-Verzeichnis>/server-%i.log" 
                append="true">
      <PatternLayout pattern="%d %p [%c] - %m%n"/>
      <Policies>
        <SizeBasedTriggeringPolicy size="5 MB"/>
                </Policies>
          <DefaultRolloverStrategy max="20"/>
    </RollingFile>
    <RollingFile name="SQLLog" fileName="<Nuclos-Log-Verzeichnis>/sql.log"
                filePattern="<Nuclos-Log-Verzeichnis>/sql-%i.log" 
                append="true">
      <PatternLayout pattern="%d %p [%c] - %m%n"/>
      <Policies>
        <SizeBasedTriggeringPolicy size="5 MB"/>
                </Policies>
          <DefaultRolloverStrategy max="20"/>
    </RollingFile>
  </Appenders>
  <Loggers>
    <Logger name="org.apache.log4j.xml" level="info"/>
    <Logger name="SQLLogger" level="debug"> 
      <AppenderRef ref="SQLLog"/>
    </Logger>
    <Root
	<Root level="info">
      <AppenderRef ref="Console"/>
      <AppenderRef ref="Logfile"/>
    </Root>
  </Loggers>
</Configuration>

Die Datei log4jlog4j2.propierties xml ist im "conf" Verzeichnis des Servers zu finden, zusammen mit den Dateien jdbc.properties und server.properties. Dabei werden mit folgenden Einstellungen des log4j-Loggers alle relevanten Informationen ausgegebenAlternativ (oder additional) kann noch "SQLTiming" angeschalten werden:

Codeblock
log4j.appender.stdout.layout.ConversionPattern=%d %-5p %-9t [%c{3}] - %m%n
log4j.rootLogger=INFO, stdout, logfile

Die Ausgabe des SQL Statements vor der Ausführung erscheint dann in der Datei server.log im Verzeichnis logs und sieht z.B. folgendermaßen aus:

Codeblock
2013-06-27 14:44:09,567 DEBUG pool-2-thread-1 [SQLLogger] - SELECT t.INTID, t.DATCREATED, t.STRCREATED, t.DATCHANGED, t.STRCHANGED, t.INTVERSION, t.INTNUCLETVERSION, t.STRPACKAGE, t.STRNAMESPACE, t.DESCRIPTION, t.NAME FROM T_AD_APPLICATION t WHERE (1=1 AND t.INTID IN (?))
=[40013466]

SQL Performance Logging

Zusätzlich kann noch die Zeit der einzelnen SQL-Statmens gemessen werden. Dazu muss der SQLTimer aktiviert werden:

Codeblock
#SQL logging
log4j.logger.SQLTimer=DEBUG

Damit wird das SQL Statement nach der Ausführung zusammen mit der Dauer ausgegeben:

    <Logger name="org.apache.log4j.xml" level="info"/>
    <Logger name="SQLTimer" level="debug"/>

Damit wird das SQL nach der Ausführung des Statements auf der Datenbank geloggt und die Ausführungszeit in Millisekunden mit angeben. Hier ist eine typische Ausgabe des SQLTimers:

Codeblock
2018-01-04 18:10:54,844 DEBUG 
Codeblock
2013-06-27 14:44:09,599 DEBUG pool-2-thread-1 [SQLTimer] - SELECT COUNT (t.INTID, t.DATCREATED, t.STRCREATED, t.DATCHANGED, t.STRCHANGED, t.INTVERSION, t.INTNUCLETVERSION, t.STRPACKAGE, t.STRNAMESPACE, t.DESCRIPTION, t.NAME FROM T_AD_APPLICATION) FROM D2SC_FH_LASTPOSITION t WHERE (1=1 AND t.INTID IN (?))
=[40013466]=(322 ms)

Hinweis: Es kann hilfreich sein, sowohl das Statement vor, als auch nach der Ausführung zu loggen. Insbesondere wenn Statements besonders lange dauern. Dafür werden einfach die beiden Zeilen kombiniert:

Codeblock
#SQL logging
log4j.logger.SQLLogger=DEBUG
log4j.logger.SQLTimer=DEBUG


SQL StackTrace Logging 

...

Es kann zusätzlich noch der StackTrace, sowohl vom Server, als auch vom Client, bis zur Ausführung des SQL-Statements geloggt werden. Das ist möglich für bestimmte SQL-Statements oder für alle SQL-Statements. Für bestimmte Statements kann in der ersten Methode Dafür kann  der Textfilter unter "Server Info" im Webclient verwendet werden (siehe oben): Außerdem kann in der Klasse "DataSourceExecuter" ein String-Suchbegriff eingegeben angegeben werden (auch zur Laufzeit, wenn der Server im Debug-Modus gestertet wurde):, entweder über einen Debugger durch setzen des Strings in folgender Methode

Codeblock
 privatepublic static booleanString testForFullDebug(final ConnectionRunner<?> runnergetDebugSQL() {  
     final String debugSQL = "FROM T_MD_STATE";
	 ....
}

Außerdem lässt sich das StackTrace-Logging ganz allgemein für alle SQL-Statments in der log4j.propertier steuern:

Codeblock
#SQL logging
log4j.logger.SQLLogger=DEBUG
log4j.logger.ClientStackTrace=DEBUG
log4j.logger.ServerStackTrace=DEBUG

Mit der Option "DEBUG" werden nur StackTrace Elemente, welche mit "org.nuclos" beginnen geloggt. Wenn alle Element ausgegeben werden sollen, dann sollte die Option "TRACE" verwenden werden:

Codeblock
#SQL logging
log4j.logger.SQLLogger=DEBUG
log4j.logger.ClientStackTrace=TRACE
log4j.logger.ServerStackTrace=TRACE

JDBCAppender SQL Logging

Zusätzlich (oder alternativ) lassen sich die SELECT SQL Statements direkt in eine Datenbank schreiben. Dies erledigt das Apache log4j-Framework. Dazu braucht man eine Datenbank, die nicht notwendigerweise identisch mit der Nuclos-DB sein muss. Dort muss eine Tabelle angelegt werden, z.B. für PostgreSQL (bei Oracle sollte die Spalte "MESSAGE" ein CLOB sein):

POSTGRESQL

Codeblock
CREATE TABLE <SCHEMA>.LOGS(
	DATED TIMESTAMP NOT NULL PRIMARY KEY,
	LOGGER VARCHAR(127) NOT NULL,
	LEVEL VARCHAR(15) NOT NULL,
	MESSAGE VARCHAR(10485760) NOT NULL,
	THREAD VARCHAR(4000) NOT NULL,
	TIME INTEGER,
	PARAMS VARCHAR(4000)
);

ORACLE

Codeblock
CREATE TABLE <SCHEMA>.LOGS(
	"DATED" TIMESTAMP NOT NULL PRIMARY KEY,
	"LOGGER" VARCHAR(127) NOT NULL,
	"LEVEL" VARCHAR(15) NOT NULL,
	"MESSAGE" CLOB NOT NULL,
	"THREAD" VARCHAR(4000) NOT NULL,
	"TIME" NUMBER(11),
	"PARAMS" VARCHAR(4000)
);

Dazu sind folgende Parameter in die o.g. log4j.propierties hinzuzufügen und entsprechend anzupassen.

POSTGRESQL

Codeblock
#SQL logging
log4j.logger.SQLLogger=DEBUG, DB
log4j.logger.SQLTimer=DEBUG, DB
 
#JDBCAppender
log4j.appender.DB=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.DB.driver=org.postgresql.Driver
log4j.appender.DB.URL=jdbc\:postgresql\://datenbankip\:5432/postgres
log4j.appender.DB.user=nuclos
log4j.appender.DB.password=nuclos
log4j.appender.DB.sql=INSERT INTO <SCHEMA>.LOGS VALUES('%d{yyyy-MM-dd HH:mm:ss.SSS}','%c','%p','%m','%t')
log4j.appender.DB.layout=org.apache.log4j.PatternLayout

ORACLE

Codeblock
#SQL logging
log4j.logger.SQLLogger=DEBUG, DB
log4j.logger.SQLTimer=DEBUG, DB
 
#JDBCAppender
log4j.appender.DB=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.DB.driver=oracle.jdbc.driver.OracleDriver
log4j.appender.DB.URL=jdbc:oracle:thin:@datenbankip:1521:oracle
log4j.appender.DB.user=nuclos
log4j.appender.DB.password=nuclos
log4j.appender.DB.sql=INSERT INTO <SCHEMA>.LOGS ("DATED", "LOGGER", "LEVEL", "MESSAGE", "THREAD", "TIME", "PARAMS") VALUES (to_timestamp('%d{yyyy-MM-dd HH:mm:ss.SSS}','YYYY-MM-DD HH24:MI:SS.FF3'),'%c','%p','%m','%t',0,'')
log4j.appender.DB.layout=org.apache.log4j.PatternLayout
log4j.appender.DB.commit=true

Es ist zu empfehlen, den Log-Level möglichst hoch zu setzten (wie hier "WARN") damit die DB beim Loggin nicht überlastet wird. Durch entfernen von "stdout" oder "logfile" kann das Logging auf die DB selber beschränkt werden.

Auswertung der SQLTimer Werte aus der Datenbank

Mit "SQLTimer" werden die Angaben zur verbrauchten Zeit an die Message gehängt. Um diese einfacher auszuwerten, kann folgendes DB-Statements durchgeführt werden:

POSTGRESQL

Codeblock
UPDATE <SCHEMA>.LOGS SET TIME = CAST(SUBSTRING(
MESSAGE FROM POSITION('=(' IN MESSAGE)+2 FOR POSITION(' ms)' IN MESSAGE)-POSITION('=(' IN MESSAGE)-2) AS INTEGER),
PARAMS = SUBSTRING(MESSAGE FROM POSITION('=[' IN MESSAGE)+2 FOR POSITION(']=' IN MESSAGE)-POSITION('=[' IN MESSAGE)-2),
MESSAGE = RTRIM(SUBSTRING(MESSAGE FROM 0 FOR POSITION('=[' IN MESSAGE)-1))
WHERE LOGGER = 'SQLTimer'

Hinweis: Die Syntax der Statements ist PostgreSQL-Spezifisch. Für andere Datenbanken müssen die Statements angepasst werden.

Beispiel einer möglichen Auswertung:

Codeblock
DELETE FROM <SCHEMA>.LOGS WHERE LOGGER != 'SQLTimer'
SELECT SUM(TIME) AS SUM, COUNT(TIME) AS COUNT, MESSAGE FROM <SCHEMA>.LOGS GROUP BY MESSAGE ORDER BY SUM DESC

Altes Standard SQL Logging (3.13.8 oder früher)

Um alle SQL Statements zu loggen, müssen folgende Zeilen in der log4j.properties hinzugefügt werden:

Codeblock
#SQL logging
log4j.logger.org.nuclos.server.dblayer=DEBUG
log4j.logger.org.nuclos.server.dal.processor.jdbc.impl.standard.StandardSqlDBAccess=DEBUG

Damit die neuen Parameter wirksam werden, muss der Server neu gestartet werden. Die Datei log4j.propierties ist im "conf" Verzeichnis des Servers zu finden, zusammen mit den Dateien jdbc.properties und server.properties.

Die Ausgabe erscheint dann in der Datei server.log im Verzeichnis logs und sieht z.B. folgendermaßen aus:

Codeblock
2013-02-11 10:02:28,208 DEBUG localhost-startStop-1 [impl.standard.StandardSqlDBAccess] - Query to execute:
 SELECT * FROM (SELECT entity.INTID  FROM T_MD_entity entity WHERE entity.STRentity = ?) WHERE ROWNUM <= 2
 [PSDH_Typ]

Wenn die Ausführung des SQL Statements länger als 0.1 Sekunden braucht, wird anschließend noch eine Zeitangabe (in Millisekunden) ausgegeben:

...

	return "SELECT COUNT";
} 

oder durch setzen aus dem Programm mit der statischen Methoden DataSourceExeceuter.setDebugSQL(String debugSQL)

Codeblock
DataSourceExeceuter.setDebugSQL("SELECT COUNT");


Dann werden für alle SQL Statements die "SELECT COUNT" beinhaltet zwei erweiterte Stacktraces ausgegeben:

Codeblock
2018-01-04 18:10:54,843 DEBUG [ServerStackTrace] - Server Stack Trace:
org.nuclos.server.dblayer.impl.DataSourceExecutor.logStackTrace(DataSourceExecutor.java:179)
org.nuclos.server.dblayer.impl.DataSourceExecutor.beforeExecution(DataSourceExecutor.java:139)
org.nuclos.server.dblayer.impl.DataSourceExecutor.execute(DataSourceExecutor.java:230)
org.nuclos.server.dblayer.impl.standard.StandardSqlDBAccess.executeQueryImpl(StandardSqlDBAccess.java:295)
org.nuclos.server.dblayer.impl.standard.StandardSqlDBAccess.executeQuery(StandardSqlDBAccess.java:274)
org.nuclos.server.dblayer.impl.standard.StandardSqlDBAccess.executeQuery(StandardSqlDBAccess.java:262)
org.nuclos.server.dblayer.impl.standard.StandardSqlDBAccess.executeQuerySingleResult(StandardSqlDBAccess.java:400)
org.nuclos.server.dal.processor.jdbc.impl.EntityObjectProcessor.countExact(EntityObjectProcessor.java:647)
org.nuclos.server.dal.processor.jdbc.impl.EntityObjectProcessor.count(EntityObjectProcessor.java:625)
org.nuclos.server.common.ejb3.EntityObjectFacadeBean.countEntityObjectRows_aroundBody14(EntityObjectFacadeBean.java:297)
org.nuclos.server.common.ejb3.EntityObjectFacadeBean$AjcClosure15.run(EntityObjectFacadeBean.java:1)
org.nuclos.server.common.ejb3.EntityObjectFacadeBean.countEntityObjectRows(EntityObjectFacadeBean.java:293)
org.nuclos.server.common.NuclosRemoteInvocationExecutor.invoke(NuclosRemoteInvocationExecutor.java:207)
org.nuclos.server.common.NuclosHttpInvokerServiceExporter.invokeAndCreateResult(NuclosHttpInvokerServiceExporter.java:13)
 
2018-01-04 18:10:54,843 DEBUG [ServerStackTrace] - Client Stack Trace:
org.nuclos.client.remote.http.NuclosHttpInvokerProxyFactoryBean.executeRequest(NuclosHttpInvokerProxyFactoryBean.java:93)
org.nuclos.common.cache.AllEntityObjectsCache.refill(AllEntityObjectsCache.java:125)
org.nuclos.common.cache.AllEntityObjectsCache.register(AllEntityObjectsCache.java:118)
org.nuclos.common.cache.AllEntityObjectsCache.register(AllEntityObjectsCache.java:105)
de.bmw.fdm.common.fh.gaal.LastfallCommonCache.init(LastfallCommonCache.java:76)
org.nuclos.client.main.StartUp$1.run(StartUp.java:388)

Hinweis: Der Client Stack Trace ist nur erhältlich, wenn der Server im Entwicklungsmodus (-Dfunctionblock.dev=true) gestartet worden ist.

SQL Logging in separates Log-File

Hier steht, wie man SQL Logging in separates Log-File konfiguriert.


SQL Logging für alte Nuclos-Versionen (bis 4.5)

Hier sind die Logging-Einstellung für Nuclos bis 4.5 zu finden: Altes SQL Logging (Bis Nuclos 4.5)