<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://helper.ch/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Silvan</id>
	<title>Helper - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="https://helper.ch/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Silvan"/>
	<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Spezial:Beitr%C3%A4ge/Silvan"/>
	<updated>2026-06-21T20:00:41Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.41.1</generator>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Sentry&amp;diff=9533</id>
		<title>Sentry</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Sentry&amp;diff=9533"/>
		<updated>2026-06-18T12:45:33Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- MediaWiki source for page: Sentry --&amp;gt;&lt;br /&gt;
&amp;lt;!-- Upload required files before publishing: Sentry-issue.png, Sentry-stack.png, Sentry-tags.png, Sentry-projects.png, Demo-window.svg, Demo-dsn.svg --&amp;gt;&lt;br /&gt;
__NOTOC__&lt;br /&gt;
== Inhaltsverzeichnis ==&lt;br /&gt;
* [[#Überblick|Überblick]]&lt;br /&gt;
* [[#Installation|Installation]]&lt;br /&gt;
* [[#Quickstart|Quickstart]]&lt;br /&gt;
* [[#Events erfassen|Events erfassen]]&lt;br /&gt;
* [[#Eigene Exceptions standardisieren|Eigene Exceptions standardisieren]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags, Extras und User-Kontext]]&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace und Kontext]]&lt;br /&gt;
* [[#Interne Architektur|Interne Architektur]]&lt;br /&gt;
* [[#Demo Library|Demo Library]]&lt;br /&gt;
* [[#API Reference|API Reference]]&lt;br /&gt;
* [[#Troubleshooting|Troubleshooting]]&lt;br /&gt;
&lt;br /&gt;
== Überblick ==&lt;br /&gt;
&lt;br /&gt;
OSentry ist ein REST-API-Konnektor von Omnis Studio zu Sentry. Der Konnektor sendet Fehler, Messages, Logs und Laufzeitkontext aus Omnis-Anwendungen an Sentry, damit Probleme in produktiven Systemen sichtbar, gruppierbar und analysierbar werden.&lt;br /&gt;
&lt;br /&gt;
Diese Dokumentation beschreibt die [[#Installation|Installation]], die Nutzung in bestehenden Omnis-Anwendungen, die Definition eigener standardisierter Exception-Typen, die interne Struktur und die [[#Demo Library|Demo-Library]].&lt;br /&gt;
&lt;br /&gt;
=== Kernidee ===&lt;br /&gt;
&lt;br /&gt;
OSentry besteht aus zwei produktiv relevanten Klassen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;: High-Level-Adapter für die Anwendung. Diese Klasse sollte von normalem Applikationscode aufgerufen werden.&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;: Low-Level-Adapter für DSN-Parsing, JSON-Erzeugung, [[#Stacktrace und Kontext|Stacktrace]]-Aufbereitung und HTTP-Kommunikation mit Sentry.&lt;br /&gt;
&lt;br /&gt;
Die Anwendung arbeitet im Normalfall mit &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;. Dadurch bleiben Sentry-spezifische Details zentral gekapselt und neue standardisierte Exception-Typen können als eigene Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Hauptfeatures ===&lt;br /&gt;
&lt;br /&gt;
* Direkte Anbindung von Omnis Studio an Sentry über REST API und DSN&lt;br /&gt;
* Erfassen von Exceptions, Messages, Logs und SQL-Fehlern&lt;br /&gt;
* Unterstützung der Sentry-Level &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
* Automatische Omnis-Kontextinformationen&lt;br /&gt;
* Omnis-[[#Stacktrace und Kontext|Stacktrace]] mit Klassen, Methoden, Zeilen und Variablen&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]] für Filterung und Gruppierung&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]] für zusätzliche Diagnoseinformationen&lt;br /&gt;
* Optionaler [[#Tags, Extras und User-Kontext|User-Kontext]]&lt;br /&gt;
* Proxy-Unterstützung&lt;br /&gt;
* Aktivieren und Deaktivieren der Sentry-Übertragung&lt;br /&gt;
* Lokales Speichern von Reports bei Übertragungsfehlern&lt;br /&gt;
&lt;br /&gt;
=== Weiterführende Links ===&lt;br /&gt;
&lt;br /&gt;
* [https://sentry.io/welcome/ Sentry Website]&lt;br /&gt;
* [https://sentry.io/signup/ Sentry Account erstellen]&lt;br /&gt;
* [https://develop.sentry.dev/self-hosted/ Sentry self-hosted]&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite beschreibt, wie OSentry in eine bestehende Omnis-Anwendung integriert wird.&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* Omnis Studio Anwendung&lt;br /&gt;
* Sentry Account oder self-hosted Sentry Installation&lt;br /&gt;
* Ein Sentry-Projekt mit SDK-Typ &amp;lt;code&amp;gt;Other&amp;lt;/code&amp;gt;&lt;br /&gt;
* Die DSN des Sentry-Projekts&lt;br /&gt;
* Netzwerkzugriff auf Sentry&lt;br /&gt;
&lt;br /&gt;
Die exportierte [[#Demo Library|Demo-Library]] wurde mit Omnis &amp;lt;code&amp;gt;11.1&amp;lt;/code&amp;gt; erstellt.&lt;br /&gt;
&lt;br /&gt;
=== Sentry-Projekt erstellen ===&lt;br /&gt;
&lt;br /&gt;
# In Sentry ein neues Projekt erstellen.&lt;br /&gt;
# Als SDK &amp;lt;code&amp;gt;Other&amp;lt;/code&amp;gt; auswählen.&lt;br /&gt;
# Die DSN des Projekts kopieren.&lt;br /&gt;
&lt;br /&gt;
Die DSN wird beim Initialisieren verwendet. &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; zerlegt sie intern in Public Key, Host und Project ID.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-projects.png|900px|Sentry Projektübersicht]]&lt;br /&gt;
&lt;br /&gt;
=== Klassen kopieren ===&lt;br /&gt;
&lt;br /&gt;
Kopiere die folgenden Klassen in deine bestehende Omnis-Library:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Demo-spezifischen Klassen sind für die produktive Integration nicht erforderlich. Damit sind die übrigen Klassen der Demo-Library gemeint, zum Beispiel &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt;. Diese Klassen dienen nur dazu, die [[#Demo Library|Demo-Library]] mit Fenster, SQLite-Testdaten und Beispielaufrufen auszuführen.&lt;br /&gt;
&lt;br /&gt;
=== Task Variable anlegen ===&lt;br /&gt;
&lt;br /&gt;
Lege in deiner Startup Task eine Task Variable an:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Name !! Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; sollte als global erreichbarer Singleton der Anwendung verwendet werden. In Omnis ist dafür eine Task Variable sinnvoll, weil sie von Fenstern, Objektklassen und zentralen Error-Handlern aus konsistent erreichbar ist. Dadurch gibt es genau eine aktive Sentry-Konfiguration mit einer DSN, einem Status, optionalen Proxy-Daten und gemeinsamen Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im [[#Demo Library|Demo-Projekt]] ist diese Variable in &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; definiert.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung im Startup Task ===&lt;br /&gt;
&lt;br /&gt;
Initialisiere &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; beim Start deiner Anwendung mit der DSN deines Sentry-Projekts:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;&amp;lt;DSN&amp;gt;&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die [[#Demo Library|Demo-Library]] ruft im Startup Task ebenfalls die Initialisierung auf. Quelle: &amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init Sentry on lbs startup&lt;br /&gt;
Do tSentry.$init()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In einer produktiven Anwendung sollte die DSN explizit oder aus einer Konfiguration übergeben werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;https://PUBLIC_KEY@sentry.io/PROJECT_ID&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; Speichere die DSN in einer Datenbank, einer Konfigurationstabelle oder einem Config File. So kann sie pro Kunde, Umgebung oder Installation geändert werden, ohne die Library neu auszuliefern.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Testcall ===&lt;br /&gt;
&lt;br /&gt;
Nach der Initialisierung kann ein erstes Testevent gesendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello World!&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles korrekt eingerichtet ist, erscheint das Event im Sentry-Projekt.&lt;br /&gt;
&lt;br /&gt;
=== Proxy konfigurieren ===&lt;br /&gt;
&lt;br /&gt;
Falls die Anwendung in einem geschützten Netzwerk läuft, kann ein Proxy gesetzt werden. Die Methode befindet sich im Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.iOSentry.$setProxy(&#039;proxy.example.local&#039;,&#039;8080&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die interne Implementierung setzt den Proxy vor dem HTTP-Request:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Configure proxy; needed when sending data out of secured networks&lt;br /&gt;
If not(isclear(iProxyHost))&amp;amp;not(isclear(iProxyPort))&lt;br /&gt;
	HTTPSetProxyServer (iProxyHost,iProxyPort)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sentry aktivieren oder deaktivieren ===&lt;br /&gt;
&lt;br /&gt;
OSentry kann zentral ein- oder ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; Deaktiviere Sentry in der Entwicklungs-Version standardmäßig oder verwende eine separate Entwicklungs-DSN. So landen lokale Tests, Debug-Fehler und absichtlich ausgelöste Exceptions nicht im produktiven Sentry-Projekt.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$setStatus(1)     ## aktiv&lt;br /&gt;
Do tSentry.$setStatus(0)     ## inaktiv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; wird vor dem Senden geprüft:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Check if Sentry is enabled&lt;br /&gt;
If iStatus=0|isclear(iStatus)&lt;br /&gt;
	Quit method 0&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite zeigt die minimale Integration in eine bestehende Omnis-Anwendung.&lt;br /&gt;
&lt;br /&gt;
=== Klassen übernehmen ===&lt;br /&gt;
&lt;br /&gt;
Kopiere &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; in deine Library.&lt;br /&gt;
&lt;br /&gt;
=== Task Variable erstellen ===&lt;br /&gt;
&lt;br /&gt;
In der Startup Task:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Name !! Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sentry initialisieren ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;https://PUBLIC_KEY@sentry.io/PROJECT_ID&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL.$init&amp;lt;/code&amp;gt; delegiert an das Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init of the main sentry object&lt;br /&gt;
Do iOSentry.$init(pDSN)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message senden ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die [[#Demo Library|Demo-Library]] verwendet genau diesen Aufruf im Button &amp;lt;code&amp;gt;Trigger a message&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.message.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exception senden ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== In Sentry prüfen ===&lt;br /&gt;
&lt;br /&gt;
In Sentry sollte anschließend ein neues Event sichtbar sein. Je nach Event-Typ enthält es:&lt;br /&gt;
&lt;br /&gt;
* Message&lt;br /&gt;
* Level&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|User-Kontext]]&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]]&lt;br /&gt;
* Omnis-Kontextinformationen&lt;br /&gt;
&lt;br /&gt;
== Events erfassen ==&lt;br /&gt;
&lt;br /&gt;
OSentryHL ist die empfohlene Einstiegsschicht für Applikationscode. Die Klasse bietet sprechende Methoden für typische Event-Arten und ruft intern &amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
&lt;br /&gt;
=== Message ===&lt;br /&gt;
&lt;br /&gt;
Eine einfache Information wird mit &amp;lt;code&amp;gt;$captureMessage&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello World!&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an Info Message&lt;br /&gt;
Do iOSentry.$captureException(pMessage,3,,&#039;info&#039;,kFalse,,kFalse) Returns code&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Level: &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;&lt;br /&gt;
* Kein [[#Stacktrace und Kontext|Stacktrace]]&lt;br /&gt;
* Kein [[#Tags, Extras und User-Kontext|User Interface]]&lt;br /&gt;
* Geeignet für einfache Statusmeldungen oder technische Hinweise&lt;br /&gt;
&lt;br /&gt;
=== Log ===&lt;br /&gt;
&lt;br /&gt;
Ein Log-Event wird mit &amp;lt;code&amp;gt;$captureLog&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureLog(&#039;Uh oh this is a Log because something went wrong&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a Log Sentry Report&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;Log&#039;,&#039;warning&#039;,1,0,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Level: &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]] aktiv&lt;br /&gt;
* Exception Interface in diesem Wrapper deaktiviert&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|User Interface]] aktiv&lt;br /&gt;
&lt;br /&gt;
=== Generische Exception ===&lt;br /&gt;
&lt;br /&gt;
Eine generische Exception wird mit &amp;lt;code&amp;gt;$captureException&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture a generic Exception&lt;br /&gt;
#Add any custom tags / extras&lt;br /&gt;
Do $cinst.$addTag(&#039;Custom Test Tag&#039;,&#039;Euromnis&#039;)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; || Text, der in Sentry als Message sichtbar ist&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; || Fehlercode oder fachlicher Code&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExcType&amp;lt;/code&amp;gt; || Exception-Typ für Benennung und Gruppierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pLevel&amp;lt;/code&amp;gt; || Sentry-Level&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Gültige Levels:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception ===&lt;br /&gt;
&lt;br /&gt;
SQL-Fehler können mit &amp;lt;code&amp;gt;$captureSQLException&amp;lt;/code&amp;gt; gemeldet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureSQLException(&#039;SQL statement failed&#039;,stat)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Fügt die Datenbank als [[#Tags, Extras und User-Kontext|Tag]] hinzu&lt;br /&gt;
* Fügt SQL-Text als [[#Tags, Extras und User-Kontext|Extra]] hinzu&lt;br /&gt;
* Fügt native Datenbankfehlermeldung als [[#Tags, Extras und User-Kontext|Extra]] hinzu&lt;br /&gt;
* Sendet das Event als &amp;lt;code&amp;gt;SQL-Exception&amp;lt;/code&amp;gt; mit Level &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deprecated Call ===&lt;br /&gt;
&lt;br /&gt;
Veraltete Codepfade können gezielt gemeldet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureDeprecatedCall()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Wrapper eignet sich, um zu erkennen, ob alter Code in produktiven Systemen noch ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
=== Frei konfigurierbares Event ===&lt;br /&gt;
&lt;br /&gt;
Für Sonderfälle gibt es &amp;lt;code&amp;gt;$captureAnything&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureAnything(&#039;Text&#039;,1001,&#039;Custom Type&#039;,&#039;error&#039;,kTrue,kTrue,kTrue)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Capture a generic Sentry Report (max configurability)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Methode bietet maximale Flexibilität. Für wiederkehrende Exception-Typen sollte aber eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; angelegt werden. Siehe [[#Eigene Exceptions standardisieren|04 Eigene Exceptions standardisieren]].&lt;br /&gt;
&lt;br /&gt;
== Eigene Exceptions standardisieren ==&lt;br /&gt;
&lt;br /&gt;
Wenn ein Exception-Typ mehrfach in der Anwendung vorkommt, sollte er nicht überall manuell mit &amp;lt;code&amp;gt;$captureException&amp;lt;/code&amp;gt; aufgebaut werden. Besser ist eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dadurch entsteht eine zentrale, wiederverwendbare Definition für:&lt;br /&gt;
&lt;br /&gt;
* Exception-Typ&lt;br /&gt;
* Sentry-Level&lt;br /&gt;
* Fehlercode&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]]&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]]/[[#Tags, Extras und User-Kontext|User]]/Exception Interface&lt;br /&gt;
&lt;br /&gt;
Die automatisch gesetzten [[#Tags, Extras und User-Kontext|Tags und Extras]] aus &amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; müssen in solchen Wrappern nicht erneut ergänzt werden. Eigene Exception-Methoden setzen nur zusätzliche Werte, die für diesen standardisierten Exception-Typ relevant sind.&lt;br /&gt;
&lt;br /&gt;
=== Warum über OSentryHL? ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ist die Abstraktionsschicht für Applikationscode. Sie kapselt die Details von &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und sorgt dafür, dass Aufrufe in der Anwendung kurz und konsistent bleiben.&lt;br /&gt;
&lt;br /&gt;
Bestehende Beispiele aus &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Empfohlenes Muster ===&lt;br /&gt;
&lt;br /&gt;
Für jeden standardisierten Exception-Typ wird eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; erstellt.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a validation exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Field&#039;,pField)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Invalid Value&#039;,pValue)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,2001,&#039;Validation-Exception&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mögliche Parameter der neuen Methode:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Beispiel !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;Invalid customer number&#039;&amp;lt;/code&amp;gt; || Sentry Message&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pModule&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;Customer&#039;&amp;lt;/code&amp;gt; || Filterbarer Tag&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pField&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;cu_number&#039;&amp;lt;/code&amp;gt; || Diagnoseinformation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pValue&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;ABC&#039;&amp;lt;/code&amp;gt; || Diagnoseinformation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der Applikationscode bleibt dadurch einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureValidationException(&#039;Invalid customer number&#039;,&#039;Customer&#039;,&#039;cu_number&#039;,cu_number)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel: Business Rule Exception ===&lt;br /&gt;
&lt;br /&gt;
Neue Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a business rule violation&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addTag(&#039;Business Rule&#039;,pRuleName)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Details&#039;,pDetails)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aufruf in der Anwendung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureBusinessRuleViolation(&#039;Invoice cannot be posted&#039;,&#039;Invoice&#039;,&#039;PostingAllowed&#039;,&#039;Invoice is missing customer&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel: Integration Exception ===&lt;br /&gt;
&lt;br /&gt;
Neue Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an integration exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Integration&#039;,pSystem)&lt;br /&gt;
Do $cinst.$addTag(&#039;Endpoint&#039;,pEndpoint)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Payload&#039;,pPayload)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Response&#039;,pResponse)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,4001,&#039;Integration-Exception&#039;,&#039;error&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aufruf in der Anwendung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureIntegrationException(&#039;External API request failed&#039;,&#039;ERP&#039;,&#039;/api/customer&#039;,jsonPayload,responseText)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Namenskonventionen ===&lt;br /&gt;
&lt;br /&gt;
Empfehlung für neue Methoden:&lt;br /&gt;
&lt;br /&gt;
* Methodenname beginnt mit &amp;lt;code&amp;gt;$capture&amp;lt;/code&amp;gt;&lt;br /&gt;
* Der fachliche Typ steht im Methodennamen&lt;br /&gt;
* Der Sentry Exception Type ist stabil und ändert sich nicht laufend&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]] sind kurz und filterbar&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]] dürfen länger sein und Diagnoseinformationen enthalten&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureValidationException&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureBusinessRuleViolation&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureIntegrationException&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$capturePermissionViolation&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureConfigurationError&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error Codes ===&lt;br /&gt;
&lt;br /&gt;
Verwende feste Fehlercodes für standardisierte Exception-Typen. Dadurch können Events in Sentry besser gefiltert und wiedererkannt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Code !! Exception Type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Validation-Exception&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Business-Rule-Violation&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Integration-Exception&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;5001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Configuration-Error&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wann nicht standardisieren? ===&lt;br /&gt;
&lt;br /&gt;
Nicht jeder Einzelfall braucht eine eigene Methode. Für einmalige technische Tests oder sehr spezielle Fälle reicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald ein Exception-Typ aber mehrfach vorkommt oder fachlich relevant ist, sollte er als eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
== Tags, Extras und User-Kontext ==&lt;br /&gt;
&lt;br /&gt;
Tags, Extras und User-Kontext reichern Sentry-Events mit zusätzlichen Informationen an. Diese Informationen helfen beim Filtern, Gruppieren und Analysieren.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-tags.png|900px|Sentry Tags und User-Kontext]]&lt;br /&gt;
&lt;br /&gt;
=== Tags ===&lt;br /&gt;
&lt;br /&gt;
Tags sind kurze, filterbare Werte.&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* Datenbank&lt;br /&gt;
* Kunde&lt;br /&gt;
* Modul&lt;br /&gt;
* Umgebung&lt;br /&gt;
* Error Code&lt;br /&gt;
* Omnis-Version&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add a Tag to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addTag(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Adds a tag to the next request processed&lt;br /&gt;
Do iTagList.$add(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$addTag(&#039;Module&#039;,&#039;Invoice&#039;)&lt;br /&gt;
Do tSentry.$addTag(&#039;Customer&#039;,&#039;10001&#039;)&lt;br /&gt;
Do tSentry.$captureException(&#039;Invoice posting failed&#039;,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Extras ===&lt;br /&gt;
&lt;br /&gt;
Extras sind Detailinformationen, die nicht primär zum Filtern gedacht sind.&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* SQL-Text&lt;br /&gt;
* Native Datenbankfehlermeldung&lt;br /&gt;
* Payload&lt;br /&gt;
* Response Body&lt;br /&gt;
* interne IDs&lt;br /&gt;
* zusätzliche Debug-Informationen&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add an Extra to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addExtra(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Adds extra information to the next request being processed&lt;br /&gt;
Do iExtraList.$add(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel aus der SQL Exception:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Automatische Tags ===&lt;br /&gt;
&lt;br /&gt;
Die folgenden Tags werden bei jedem Event automatisch von &amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; ergänzt. Sie müssen bei eigenen Exceptions nicht erneut gesetzt werden. Eigene Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; sollten nur zusätzliche, fachlich oder technisch relevante Tags hinzufügen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; fügt mehrere Tags automatisch hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add static tags&lt;br /&gt;
Do iTagList.$add(&#039;Omnisversion&#039;,sys(1))&lt;br /&gt;
Calculate systemversionRow as systemversion()&lt;br /&gt;
Do iTagList.$add(&#039;Plattform&#039;,con(sys(8),pick(systemversionRow.server,&#039;&#039;,&#039; SRV&#039;)))&lt;br /&gt;
Do iTagList.$add(&#039;OS Version&#039;,con(systemversionRow.major,&#039;.&#039;,systemversionRow.minor,&#039;.&#039;,systemversionRow.build))&lt;br /&gt;
Do iTagList.$add(&#039;error_code&#039;,pErrorCode)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Automatisch gesendete Tags:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tag !! Herkunft !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Omnisversion&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;sys(1)&amp;lt;/code&amp;gt; || Zeigt, mit welcher Omnis-Version das Event erzeugt wurde&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Plattform&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;sys(8)&amp;lt;/code&amp;gt; und Server-Flag aus &amp;lt;code&amp;gt;systemversion()&amp;lt;/code&amp;gt; || Unterscheidet Plattform und Server Runtime&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OS Version&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;systemversionRow.major/minor/build&amp;lt;/code&amp;gt; || Zeigt die Betriebssystemversion&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;error_code&amp;lt;/code&amp;gt; || Parameter &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; || Verbindet das Event mit dem übergebenen Fehlercode&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Beispiel für eine eigene Exception: Der Wrapper muss nicht erneut &amp;lt;code&amp;gt;Omnisversion&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;OS Version&amp;lt;/code&amp;gt; setzen. Er ergänzt nur das, was für diesen Exception-Typ zusätzlich hilfreich ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addTag(&#039;Business Rule&#039;,pRuleName)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Automatische Extras ===&lt;br /&gt;
&lt;br /&gt;
Auch die folgenden Extras werden bei jedem Event automatisch ergänzt. Bei eigenen Exceptions müssen nur zusätzliche Extras gesetzt werden, zum Beispiel ein SQL-Statement, ein Payload oder fachliche Zusatzdaten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; fügt offene Fenster, offene Reports und die aktuelle Printfile hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Static extra 1: All open windows&lt;br /&gt;
Do $root.$iwindows.$makelist($ref.$name) Returns nameList&lt;br /&gt;
For i from 1 to nameList.$linecount step 1&lt;br /&gt;
	Calculate windows as con(windows,&#039;, &#039;,nameList.[i].1)&lt;br /&gt;
End For&lt;br /&gt;
Calculate windows as right(windows,len(windows)-2)&lt;br /&gt;
Do iExtraList.$add(&#039;Open Windows&#039;,windows)&lt;br /&gt;
&lt;br /&gt;
# Static extra 2: All open reports&lt;br /&gt;
Do $root.$ireports.$makelist($ref.$name) Returns nameList&lt;br /&gt;
For i from 1 to nameList.$linecount step 1&lt;br /&gt;
	Calculate reports as con(reports,&#039;, &#039;,nameList.[i].1)&lt;br /&gt;
End For&lt;br /&gt;
Calculate reports as right(reports,len(reports)-2)&lt;br /&gt;
Do iExtraList.$add(&#039;Open Reports&#039;,reports)&lt;br /&gt;
Do iExtraList.$add(&#039;Current Printfile&#039;,$root.$prefs.$printfile)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Automatisch gesendete Extras:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Extra !! Herkunft !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Open Windows&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$iwindows.$makelist($ref.$name)&amp;lt;/code&amp;gt; || Zeigt, welche Fenster im Moment des Events offen waren&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Open Reports&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$ireports.$makelist($ref.$name)&amp;lt;/code&amp;gt; || Zeigt, welche Reports im Moment des Events offen waren&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Current Printfile&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$prefs.$printfile&amp;lt;/code&amp;gt; || Zeigt die aktuell gesetzte Printfile&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Beispiel für zusätzliche Extras in einem eigenen Wrapper:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addExtra(&#039;Payload&#039;,pPayload)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Response&#039;,pResponse)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,4001,&#039;Integration-Exception&#039;,&#039;error&#039;,1,1,1) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== User-Kontext ===&lt;br /&gt;
&lt;br /&gt;
Der User-Kontext ordnet ein Event einem betroffenen Benutzer zu. In Sentry erscheint dadurch ein eigener User-Bereich, und Events können nach Benutzer gefiltert oder gruppiert werden. Das ist besonders hilfreich, wenn ein Fehler nur bei einzelnen Kunden, Arbeitsplätzen oder Benutzerkonten auftritt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; unterstützt drei User-Felder:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feld !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt; || stabile interne Benutzer-ID oder Kundennummer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;username&amp;lt;/code&amp;gt; || lesbarer Benutzername&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;email&amp;lt;/code&amp;gt; || E-Mail-Adresse, falls sie übertragen werden darf&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der User-Kontext wird nur in das Event geschrieben, wenn das User Interface beim Capture-Aufruf aktiviert ist. Die Standardmethode &amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; hat &amp;lt;code&amp;gt;pUserInterface&amp;lt;/code&amp;gt; standardmäßig auf &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt;. Einzelne High-Level-Methoden können das bewusst deaktivieren, zum Beispiel &amp;lt;code&amp;gt;$captureMessage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; kann User-Daten an das Event anhängen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Sets userinformation for the next request being processed&lt;br /&gt;
Calculate iUserID as pID&lt;br /&gt;
Calculate iUserName as pName&lt;br /&gt;
Calculate iUserEmail as pEmail&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das User Interface wird so generiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Create user data row&lt;br /&gt;
Do UserdataRow.$define(id,email,username)&lt;br /&gt;
&lt;br /&gt;
Calculate UserdataRow.id as iUserID&lt;br /&gt;
Calculate UserdataRow.email as iUserEmail&lt;br /&gt;
Calculate UserdataRow.username as iUserName&lt;br /&gt;
&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;user&#039;,&#039;&#039;)&lt;br /&gt;
Do JSON.$setobject(&#039;user&#039;,UserdataRow)&lt;br /&gt;
&lt;br /&gt;
Calculate jsonString as OJSON.$formatjson(JSON.$getjson())&lt;br /&gt;
&lt;br /&gt;
Quit method jsonString&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die aktuelle Demo-Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; verwendet feste Testdaten. Quelle: &amp;lt;code&amp;gt;OSentryHL.$setUser&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Set the User which should be linked to the Sentry Issue&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte diese Methode angepasst und parametrisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(pUserID,pUserName,pUserEmail)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Empfohlen ist, den User nach Login oder beim Wechsel des aktiven Benutzers zentral zu setzen. Bei anonymen oder sensiblen Installationen kann statt Name und E-Mail auch nur eine interne ID oder ein pseudonymisierter Wert verwendet werden.&lt;br /&gt;
&lt;br /&gt;
=== Datenschutz ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #72777d; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Datenschutz:&#039;&#039;&#039; Prüfe vor produktiver Nutzung, welche Daten an Sentry gesendet werden. Besonders kritisch sind personenbezogene Daten, SQL-Statements, Zugangsdaten, Tokens und interne Pfade.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Besonders kritisch sind:&lt;br /&gt;
&lt;br /&gt;
* personenbezogene Daten&lt;br /&gt;
* Kundendaten&lt;br /&gt;
* SQL-Statements mit Werten&lt;br /&gt;
* Zugangsdaten&lt;br /&gt;
* Tokens&lt;br /&gt;
* interne Pfade&lt;br /&gt;
&lt;br /&gt;
Tags und Extras sollten so gestaltet werden, dass sie für die Fehleranalyse hilfreich sind, aber keine unnötigen sensiblen Daten übertragen.&lt;br /&gt;
&lt;br /&gt;
== Stacktrace und Kontext ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; erzeugt einen Omnis-spezifischen Stacktrace und übergibt ihn an Sentry. Dadurch sieht man in Sentry nicht nur eine Fehlermeldung, sondern auch Klassen, Methoden, Zeilen und Variablenkontext. Ergänzende Informationen zu [[#Tags, Extras und User-Kontext|Tags, Extras und User-Kontext]] stehen auf der separaten Kontext-Seite.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-stack.png|900px|Sentry Stacktrace mit Omnis-Kontext]]&lt;br /&gt;
&lt;br /&gt;
=== Stack lesen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateStacktraceInterface&amp;lt;/code&amp;gt; verwendet &amp;lt;code&amp;gt;sys(192)&amp;lt;/code&amp;gt;, um den aktuellen Omnis-Stack zu lesen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Clean up the Stacklist (remove OSentry classes from the stack)&lt;br /&gt;
Do sys(192) Returns sys192List&lt;br /&gt;
For sys192List.$line from 1 to sys192List.$linecount step 1&lt;br /&gt;
	Set reference class to sys192List.classitem&lt;br /&gt;
	If pos(&#039;OSentry&#039;,class.$name)&amp;gt;0|pos(&#039;OSentryHL&#039;,class.$name)&amp;gt;0&lt;br /&gt;
		Do sys192List.[sys192List.$line].$selected.$assign(kTrue)&lt;br /&gt;
	End If&lt;br /&gt;
End For&lt;br /&gt;
Do sys192List.$remove(kListDeleteSelected)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Interne Frames von &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; werden entfernt, damit in Sentry die fachlich relevanten Stellen sichtbar bleiben.&lt;br /&gt;
&lt;br /&gt;
=== SQL-Error Frames entfernen ===&lt;br /&gt;
&lt;br /&gt;
Bestimmte interne SQL-Fehlerframes werden ebenfalls entfernt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Remove some other classes which we do not want to display&lt;br /&gt;
If sys192List.1.method=&#039;$sqlerror&#039;&lt;br /&gt;
	Do sys192List.$remove(1)&lt;br /&gt;
Else If sys192List.1.method=&#039;$statementerror&#039;&lt;br /&gt;
	Do sys192List.$remove(1)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frames erzeugen ===&lt;br /&gt;
&lt;br /&gt;
Für jeden Stack-Eintrag werden Funktion, Zeilennummer und Kontextzeile erzeugt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Loop through every item on the omnis stack&lt;br /&gt;
For sys192List.$line from 1 to sys192List.$linecount step 1&lt;br /&gt;
	Set reference class to sys192List.classitem&lt;br /&gt;
	Calculate className as class.$name&lt;br /&gt;
	&lt;br /&gt;
	# Create the content row&lt;br /&gt;
	Do contentRow.$define(vars,function,pre_context,context_line,lineno,filename,post_context)&lt;br /&gt;
	Calculate contentRow.lineno as sys192List.line&lt;br /&gt;
	Calculate contentRow.filename as testFileName&lt;br /&gt;
	Calculate contentRow.context_line as sys192List.linetext&lt;br /&gt;
	If isclear(sys192List.object)&lt;br /&gt;
		Calculate contentRow.function as con(className,&#039;.&#039;,sys192List.method) ## If it&#039;s a class method&lt;br /&gt;
	Else&lt;br /&gt;
		Calculate contentRow.function as con(className,&#039;.&#039;,sys192List.object,&#039;.&#039;,sys192List.method) ## If it&#039;s a method of an object of a class (e.g. Headedlist)&lt;br /&gt;
	End If&lt;br /&gt;
	Do contentList.$add(contentRow)&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablen aufnehmen ===&lt;br /&gt;
&lt;br /&gt;
Pro Stackframe werden Instance Variablen und Parameter gesammelt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Get all iVars&lt;br /&gt;
Do varList.$define(name,value)&lt;br /&gt;
Set reference class to sys192List.inst&lt;br /&gt;
Do $cinst.$getVars(&#039;ivars&#039;,class) Returns varList&lt;br /&gt;
&lt;br /&gt;
# Get all params&lt;br /&gt;
Calculate paramList as sys192List.params&lt;br /&gt;
For paramList.$line from 1 to paramList.$linecount step 1&lt;br /&gt;
	If not(paramList.value=&#039;(Not empty)&#039;)&lt;br /&gt;
		Do varList.$add(paramList.name,paramList.value)&lt;br /&gt;
	Else&lt;br /&gt;
		Do varList.$add(paramList.name,&#039;(Not empty)&#039;)&lt;br /&gt;
	End If&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pre- und Post-Context ===&lt;br /&gt;
&lt;br /&gt;
OSentry fügt Methodenzeilen vor und nach der aktuellen Zeile hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Pre Context (all method lines before the error occured)&lt;br /&gt;
Set reference method to sys192List.methoditem&lt;br /&gt;
Do precontextList.$define(line)&lt;br /&gt;
For i from 1 to sys192List.line-1 step 1&lt;br /&gt;
	Do precontextList.$add(method.$methodlines.[i].$text)&lt;br /&gt;
End For&lt;br /&gt;
&lt;br /&gt;
# Post Context (all method lines after the error occured&lt;br /&gt;
Do postcontextList.$define(line)&lt;br /&gt;
For i from sys192List.line+1 to method.$methodlines.$count step 1&lt;br /&gt;
	Do postcontextList.$add(method.$methodlines.[i].$text)&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablentypen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$getVars&amp;lt;/code&amp;gt; unterstützt Basisvariablen, Rows und Lists.&lt;br /&gt;
&lt;br /&gt;
Basisvariablen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
If varType=&#039;char&#039;|varType=&#039;boolean&#039;|varType=&#039;integer&#039;|varType=&#039;number&#039;|varType=&#039;date&#039;&lt;br /&gt;
	Calculate varContent as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	Do varList.$add(varName,varContent)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Else If varType=&#039;row&#039;&lt;br /&gt;
	Calculate varRow as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	If varRow.$colcount=0&lt;br /&gt;
		Do varList.$add(varName,&#039;(Empty)&#039;)&lt;br /&gt;
	Else&lt;br /&gt;
		For Z2 from 1 to varRow.$colcount step 1&lt;br /&gt;
			Calculate varContent as con(varContent,varRow.$cols.[Z2].$name,&#039;: &#039;,varRow.[Z2],&#039;, &#039;)&lt;br /&gt;
		End For&lt;br /&gt;
		Do varList.$add(varName,varContent)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lists:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Else If varType=&#039;list&#039;&lt;br /&gt;
	Calculate varListType as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	Calculate varContent as con(&#039;Colcount: &#039;,varListType.$colcount,&#039;, &#039;,&#039;Linecount: &#039;,varListType.$linecount,&#039;, &#039;,&#039;Current Line: &#039;,varListType.$line)&lt;br /&gt;
	If varListType.$linecount=0&amp;amp;varListType.$line=0&amp;amp;varListType.$colcount=0&lt;br /&gt;
		Do varList.$add(varName,&#039;(Empty)&#039;)&lt;br /&gt;
		Calculate varContent as &#039;&#039;&lt;br /&gt;
	Else&lt;br /&gt;
		For Z3 from 1 to varListType.$colcount step 1&lt;br /&gt;
			Calculate colName as varListType.$cols.[Z3].$name&lt;br /&gt;
			Calculate varContent as con(varContent,&#039;  &#039;,colName,&#039;: &#039;,varListType.[colName])&lt;br /&gt;
		End For&lt;br /&gt;
		Do varList.$add(varName,varContent)&lt;br /&gt;
		Calculate varContent as &#039;&#039;&lt;br /&gt;
	End If&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
&lt;br /&gt;
Stacktrace und Variablenkontext sind sehr hilfreich, können aber sensible Daten enthalten. Vor produktiver Nutzung sollte geprüft werden, ob bestimmte Variablen anonymisiert oder ausgeschlossen werden müssen.&lt;br /&gt;
&lt;br /&gt;
== Interne Architektur ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite beschreibt die produktiv relevanten Klassen &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Klassenübersicht ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Rolle&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; || High-Level-Adapter für Applikationscode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; || Low-Level-Adapter für JSON, [[#Stacktrace und Kontext|Stacktrace]] und HTTP&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Startup und Beispiel für Initialisierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Code für [[#Stacktrace und Kontext|Stacktrace]]-Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-DB Initialisierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt; || SQLite Session für [[#Demo Library|Demo]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Empfohlener Aufrufweg ===&lt;br /&gt;
&lt;br /&gt;
Applikationscode sollte &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; verwenden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; delegiert anschließend an &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ablauf eines Events ===&lt;br /&gt;
&lt;br /&gt;
# Applikationscode ruft Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; fügt bei Bedarf [[#Tags, Extras und User-Kontext|Tags und Extras]] hinzu.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ruft &amp;lt;code&amp;gt;iOSentry.$captureException(...)&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; prüft, ob Sentry aktiv ist.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; erzeugt JSON.&lt;br /&gt;
# [[#Stacktrace und Kontext|Stacktrace]], Exception Interface und [[#Tags, Extras und User-Kontext|User Interface]] werden optional ergänzt.&lt;br /&gt;
# HTTP Header und Sentry Auth Header werden erstellt.&lt;br /&gt;
# JSON wird per HTTPS an Sentry gesendet.&lt;br /&gt;
# Bei Erfolg werden [[#Tags, Extras und User-Kontext|Tags und Extras]] geleert.&lt;br /&gt;
# Bei Fehler wird der JSON Report lokal gespeichert.&lt;br /&gt;
&lt;br /&gt;
=== DSN Parsing ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$init&amp;lt;/code&amp;gt; zerlegt die DSN:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Parse the DSN into Public Key, Host and Project ID&lt;br /&gt;
If len(pDSN)&amp;gt;5&lt;br /&gt;
	Calculate iDSN as pDSN&lt;br /&gt;
	Calculate part1 as strtok(&#039;iDSN&#039;,&#039;@&#039;)&lt;br /&gt;
	Calculate iProtocol as strtok(&#039;part1&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iProtocol as left(iProtocol,len(iProtocol)-1)&lt;br /&gt;
	Do strtok(&#039;part1&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iPubKey as strtok(&#039;part1&#039;,&#039;:&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Calculate iHost as strtok(&#039;iDSN&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iProID as iDSN&lt;br /&gt;
	&lt;br /&gt;
	#Save the values for the next startup&lt;br /&gt;
	Calculate $cclass.$ivardefs.iPubKey.$objinitval as con(&#039;&amp;quot;&#039;,iPubKey,&#039;&amp;quot;&#039;)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iHost.$objinitval as con(&#039;&amp;quot;&#039;,iHost,&#039;&amp;quot;&#039;)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iProID.$objinitval as con(&#039;&amp;quot;&#039;,iProID,&#039;&amp;quot;&#039;)&lt;br /&gt;
End If&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== JSON-Erzeugung ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; ist die zentrale Methode für den Payload. Sie setzt unter anderem:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;event_id&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;logger&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;platform&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;culprit&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;timestamp&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sdk&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;message&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;level&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;tags&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;extra&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;exception&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;stacktrace&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auszug:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add all required fields (those are required from the API)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;event_id&#039;,$cinst.$generateUUID()) ## auto generated UUID 4&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;logger&#039;,logger)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;platform&#039;,platform)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;culprit&#039;,culprit)&lt;br /&gt;
#Do JSON.$addmember(&#039;&#039;,&#039;release&#039;,release)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;timestamp&#039;,timestamp)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;sdk&#039;,&#039;&#039;)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;message&#039;,pErrorText)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;level&#039;,pLevel)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;tags&#039;,&#039;&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== HTTP-Kommunikation ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; sendet den erzeugten JSON-Payload an Sentry:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Generate HTTP Auth header&lt;br /&gt;
Begin text block&lt;br /&gt;
Text:Sentry sentry_version=7,&lt;br /&gt;
Text:sentry_timestamp=[$cinst.$getUnixTimestamp()],&lt;br /&gt;
Text:sentry_key=[iPubKey],&lt;br /&gt;
Text:sentry_client=omnis/1.0&lt;br /&gt;
End text block&lt;br /&gt;
Get text block auth&lt;br /&gt;
&lt;br /&gt;
#Generate header list&lt;br /&gt;
Calculate Host as &#039;sentry.io&#039;&lt;br /&gt;
Calculate Url as con(&#039;/api/&#039;,iProID,&#039;/store/&#039;)&lt;br /&gt;
Do HdrList.$define(wert,name)&lt;br /&gt;
Do HdrList.$add(&#039;User-Agent&#039;,&#039;omnis/1.0&#039;)&lt;br /&gt;
Do HdrList.$add(&#039;Content-Type&#039;,&#039;application/json&#039;)&lt;br /&gt;
Do HdrList.$add(&#039;Content-Length&#039;,binlength(json))&lt;br /&gt;
Do HdrList.$add(&#039;X-Sentry-Auth&#039;,auth)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anschließend wird der Request über &amp;lt;code&amp;gt;HTTPPost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HTTPSend&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;HTTPRead&amp;lt;/code&amp;gt; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
=== Fehlerbehandlung beim Senden ===&lt;br /&gt;
&lt;br /&gt;
Wenn der Socket nicht geöffnet werden kann:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPPost (Host,Url,,HdrList,443,kTrue,kTrue) Returns Socket&lt;br /&gt;
If Socket&amp;lt;0&lt;br /&gt;
	#Error when opening connection -&amp;gt; save json as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,con(&#039;Error &#039;,Socket,&#039; when performing HTTPPost&#039;))&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -1&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn das Senden fehlschlägt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPSend (Socket,json) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0&lt;br /&gt;
	# Error while sending data -&amp;gt; save json as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,con(&#039;Erorr &#039;,byteCount,&#039; when performing HTTPSend&#039;))&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -2&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn die Antwort nicht erfolgreich ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPRead (Socket,Buffer) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0|not(pos(&#039;200 OK&#039;,Buffer))&lt;br /&gt;
	# JSON may be corrupted or contains errors -&amp;gt; save json and the buffer as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,Buffer)&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -3&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Lokales Speichern ===&lt;br /&gt;
&lt;br /&gt;
Bei Fehlern wird der JSON Report lokal im Omnis-Installationsordner gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Writes the json and the http buffer to a file in the omnis installation folder&lt;br /&gt;
Calculate path as sys(115)&lt;br /&gt;
Calculate filename as con(&#039;Sentryreport_&#039;,$cinst.$getUnixTimestamp(),&#039;.json&#039;)&lt;br /&gt;
Do fOP.$createfile(con(path,filename)) Returns err&lt;br /&gt;
Do fOP.$writecharacter(kUniTypeUTF8,pJSON) Returns err&lt;br /&gt;
If not(isclear(pBuffer))&lt;br /&gt;
	Do fOP.$writecharacter(kUniTypeUTF8,con(kCr,pBuffer),kTrue) Returns err&lt;br /&gt;
End If&lt;br /&gt;
Do fOP.$closefile()&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cleanup ===&lt;br /&gt;
&lt;br /&gt;
Nach erfolgreichem Senden werden [[#Tags, Extras und User-Kontext|Tags und Extras]] gelöscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Clears all extras and tags =&amp;gt; to be used after a sentry request has successfully been sent&lt;br /&gt;
Do iTagList.$clear()&lt;br /&gt;
Do iExtraList.$clear()&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Demo Library ==&lt;br /&gt;
&lt;br /&gt;
Die Demo-Library zeigt, wie &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; initialisiert wird und wie verschiedene [[#Events erfassen|Event-Typen]] aus einer Omnis-Oberfläche heraus an Sentry gesendet werden.&lt;br /&gt;
&lt;br /&gt;
=== Bestandteile ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; || Initialisiert Sentry, SQLite und öffnet das Demo-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; || Demo-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt; || Erzeugt Demo-Stack für Exception&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; || Erstellt SQLite-Demo-Datenbank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt; || SQLite Session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; || Low-Level-Sentry-Adapter&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; || High-Level-Sentry-Adapter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt; initialisiert Sentry, baut eine SQLite Session auf und öffnet das Demo-Fenster. Quelle: &amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init Sentry on lbs startup&lt;br /&gt;
Do tSentry.$init()&lt;br /&gt;
&lt;br /&gt;
#SQLite Session init&lt;br /&gt;
Do $objects.OSLSession.$newref() Returns tOSLSession&lt;br /&gt;
#Calculate tOSLSession.$opencreate as kTrue&lt;br /&gt;
Calculate workingDir as tODatabaseHandler.$getWorkingDir()&lt;br /&gt;
Do con(workingDir,&#039;Sentry_Test.db&#039;) Returns dbLocation&lt;br /&gt;
Do tOSLSession.$logon(dbLocation,&#039;&#039;,&#039;&#039;,&#039;slsession&#039;) Returns #F&lt;br /&gt;
&lt;br /&gt;
#Open Test Window&lt;br /&gt;
Do $windows.FSY_Demo.$openonce(&#039;*&#039;)&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Demo-Fenster ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; enthält folgende Bereiche:&lt;br /&gt;
&lt;br /&gt;
* DSN Configuration&lt;br /&gt;
* DB Status&lt;br /&gt;
* Actions&lt;br /&gt;
&lt;br /&gt;
Wichtige Felder:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feld !! Datenanbindung&lt;br /&gt;
|-&lt;br /&gt;
| DSN || &amp;lt;code&amp;gt;iDSN&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Host || &amp;lt;code&amp;gt;tSentry.iOSentry.iHost&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Public Key || &amp;lt;code&amp;gt;tSentry.iOSentry.iPubKey&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Project ID || &amp;lt;code&amp;gt;tSentry.iOSentry.iProID&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| DB Status || &amp;lt;code&amp;gt;iCurrentDBStatus&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Datei:Demo-window.png|850px|Demo-Fenster der OSentry Library]]&lt;br /&gt;
&lt;br /&gt;
=== DSN setzen ===&lt;br /&gt;
&lt;br /&gt;
Die DSN wird im Feld &amp;lt;code&amp;gt;iDSN&amp;lt;/code&amp;gt; erfasst. Der Button &amp;lt;code&amp;gt;Set DSN&amp;lt;/code&amp;gt; ruft anschließend &amp;lt;code&amp;gt;tSentry.$init(iDSN)&amp;lt;/code&amp;gt; auf. Nach dem Setzen werden Public Key, Host und Project ID aus der DSN gelesen und in den darunterliegenden Feldern angezeigt.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Demo-dsn.png|850px|DSN-Konfiguration im Demo-Fenster]]&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Set DSN&amp;lt;/code&amp;gt; initialisiert Sentry mit der eingegebenen DSN. Quelle: &amp;lt;code&amp;gt;FSY_Demo.setDSN.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$init(iDSN)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iDSN.$objinitval as con(kSq,iDSN,kSq)&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$showmessage(&#039;DSN set and Sentry initialized!&#039;,&#039;Info&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$redraw()&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== DB Status anzeigen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FSY_Demo.$displayDBState&amp;lt;/code&amp;gt; zeigt, ob die SQLite Session verbunden ist. Quelle: &amp;lt;code&amp;gt;FSY_Demo.$displayDBState&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tOSLSession.$state Returns dbState&lt;br /&gt;
If dbState=&#039;kSessionStateLoggedOff&#039;&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Logged Off&#039;&lt;br /&gt;
Else If dbState=&#039;kSessionStateLoggedOn&#039;&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Logged On&#039;&lt;br /&gt;
Else&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Unkown DB State&#039;&lt;br /&gt;
End If&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$redraw()&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Demo-Datenbank erstellen ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Create Database&amp;lt;/code&amp;gt; ruft &amp;lt;code&amp;gt;ODatabaseHandler.$DBFirstInit&amp;lt;/code&amp;gt; auf. Quelle: &amp;lt;code&amp;gt;FSY_Demo.createDB.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Setup the DB&lt;br /&gt;
	Do tODatabaseHandler.$DBFirstInit() Returns err&lt;br /&gt;
	If err=0&lt;br /&gt;
		Do $cinst.$showmessage(&#039;DB successfully created!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Else&lt;br /&gt;
		Do $cinst.$showmessage(&#039;Error while creating the DB. Make sure that the DB does not already exist.&#039;,&#039;Info&#039;)&lt;br /&gt;
	End If&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$displayDBState()&lt;br /&gt;
	&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Datenbank wird im Arbeitsverzeichnis der Library angelegt. Quelle: &amp;lt;code&amp;gt;ODatabaseHandler.$getWorkingDir&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Quit method con(FileOps.$parentdir($clib.$pathname),pathsep())&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Demo-DB enthält unter anderem:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;dperson&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;drelease&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;dvcs&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a message&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.message.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Log auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a log&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.log.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureLog(&#039;Uh oh this is a Log because something went wrong&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exception auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger an exception&amp;lt;/code&amp;gt; bereitet eine Row und eine List vor und ruft anschließend &amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt; auf. Quelle: &amp;lt;code&amp;gt;FSY_Demo.exception.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do iDummyRow.$define(id,name)&lt;br /&gt;
	Calculate iDummyRow.id as 22&lt;br /&gt;
	Calculate iDummyRow.name as &#039;Tom&#039;&lt;br /&gt;
	&lt;br /&gt;
	Do iDummyList.$define(id,weekday)&lt;br /&gt;
	Do iDummyList.$add(1,&#039;Monday&#039;)&lt;br /&gt;
	Do iDummyList.$add(2,&#039;Tuesday&#039;)&lt;br /&gt;
	Do iDummyList.$add(3,&#039;Wednesday&#039;)&lt;br /&gt;
	Do iDummyList.$add(4,&#039;Thursday&#039;)&lt;br /&gt;
	Do iDummyList.$add(5,&#039;Friday&#039;)&lt;br /&gt;
	Do iDummyList.$add(6,&#039;Saturday&#039;)&lt;br /&gt;
	Do iDummyList.$add(7,&#039;Sunday&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Calculate iDummyList.$line as 5&lt;br /&gt;
	&lt;br /&gt;
	Do iODummy.$dummyMethod(&#039;Important Value&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt; sendet die Exception. Quelle: &amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#In here is some logic&lt;br /&gt;
#This logic would produce an error&lt;br /&gt;
#We send all this information to Sentry&lt;br /&gt;
&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&lt;br /&gt;
Quit method 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deprecated Call auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a deprecated call&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.deprecatedCall.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureDeprecatedCall()&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception Button ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Trigger an SQLException&amp;lt;/code&amp;gt; ist im Export vorhanden, enthält aber noch keinen fertigen Demo-Code. Quelle: &amp;lt;code&amp;gt;FSY_Demo.sqlException.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Code need&#039;s to be written&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Dokumentation der SQL-Erfassung siehe [[#Events erfassen|03 Events erfassen]].&lt;br /&gt;
&lt;br /&gt;
== API Reference ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite dokumentiert die produktiv relevanten Methoden von &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== OSentryHL ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ist die empfohlene Klasse für Applikationscode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$init(pDSN)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Initialisiert das interne &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;-Objekt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init of the main sentry object&lt;br /&gt;
Do iOSentry.$init(pDSN)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureMessage(pMessage)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet eine einfache Info-Message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an Info Message&lt;br /&gt;
Do iOSentry.$captureException(pMessage,3,,&#039;info&#039;,kFalse,,kFalse) Returns code&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureException(pErrorText,pErrorCode,pExcType,pLevel)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet eine generische Exception.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture a generic Exception&lt;br /&gt;
#Add any custom tags / extras&lt;br /&gt;
Do $cinst.$addTag(&#039;Custom Test Tag&#039;,&#039;Euromnis&#039;)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureAnything(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet ein frei konfigurierbares Event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Capture a generic Sentry Report (max configurability)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hinweis: Der Parameter ist im Export als &amp;lt;code&amp;gt;pStacktraveInterface&amp;lt;/code&amp;gt; geschrieben.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureLog(pErrorText)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet ein Log-Event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a Log Sentry Report&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;Log&#039;,&#039;warning&#039;,1,0,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureDeprecatedCall()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Meldet die Ausführung eines veralteten Codepfads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureSQLException(pErrorText,pStat)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Meldet einen SQL-Fehler mit SQL-Text und nativer Datenbankfehlermeldung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addTag(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt einen Tag für das nächste Event hinzu.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add a Tag to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addTag(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addExtra(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt ein Extra für das nächste Event hinzu.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add an Extra to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addExtra(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setStatus(pStatus)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Aktiviert oder deaktiviert Sentry.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Toggels Sentry on or off&lt;br /&gt;
Do iOSentry.$setStatus(pStatus)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setUser()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt im Export feste [[#Demo Library|Demo]]-Userdaten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Set the User which should be linked to the Sentry Issue&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte diese Methode parametrisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== OSentry ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; ist die Low-Level-Klasse für Payload-Erzeugung und Versand.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$init(pDSN)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parst die DSN in Protokoll, Public Key, Host und Project ID.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraceInterface,pUserInterface,pExceptionInterface)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt JSON, sendet es an Sentry und behandelt Fehlerfälle.&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Default !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; ||  || Message&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; ||  || Fehlercode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExcType&amp;lt;/code&amp;gt; ||  || Exception-Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pLevel&amp;lt;/code&amp;gt; ||  || &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pStacktraceInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || [[#Stacktrace und Kontext|Stacktrace]] senden&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pUserInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || [[#Tags, Extras und User-Kontext|User-Kontext]] senden&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExceptionInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || Exception Interface senden&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateJson(...)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den Sentry JSON Payload als Binary.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateStacktraceInterface(pCulprit)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den Omnis-[[#Stacktrace und Kontext|Stacktrace]] inklusive Variablen und Kontextzeilen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateExceptionInterface(pType,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt das Sentry Exception Interface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Generate Row to store in the JSON&lt;br /&gt;
Do exceptionRow.$define(type,value,stacktrace)&lt;br /&gt;
Calculate exceptionRow.type as pType&lt;br /&gt;
Calculate exceptionRow.value as pValue&lt;br /&gt;
Calculate exceptionRow.stacktrace as &#039;sentry.interfaces.stacktrace&#039; ## Tells the exception interface that a stacktrace is passed aswell&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateUserInterface()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den [[#Tags, Extras und User-Kontext|User-Kontext]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addTag(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt einen Tag zur internen Tag-Liste hinzu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addExtra(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt ein Extra zur internen Extra-Liste hinzu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$clearList()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Leert [[#Tags, Extras und User-Kontext|Tags und Extras]] nach einem Request.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setUserData(pID,pName,pEmail)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt Userdaten für den nächsten Request.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setProxy(pProxyHost,pProxyPort)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt Proxy-Informationen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setStatus(pStatus)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt den Sentry-Status.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Toggels Sentry Reports on or off&lt;br /&gt;
Calculate iStatus as pStatus&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$writeJSON(pJSON,pBuffer)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Schreibt fehlgeschlagene Reports lokal in eine Datei.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$getUnixTimestamp()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Gibt den aktuellen UNIX Timestamp zurück.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateUUID()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt eine UUID für die Sentry Event ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Genereates a UUID for the issue id&lt;br /&gt;
Quit method OW3.$makeuuid(kFalse)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Es erscheinen keine Events in Sentry ===&lt;br /&gt;
&lt;br /&gt;
Prüfe zuerst, ob Sentry aktiv ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$setStatus(1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; beendet sich sofort, wenn der Status &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; oder leer ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Check if Sentry is enabled&lt;br /&gt;
If iStatus=0|isclear(iStatus)&lt;br /&gt;
	Quit method 0&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Die DSN ist falsch ===&lt;br /&gt;
&lt;br /&gt;
Prüfe, ob die DSN korrekt aus Sentry kopiert wurde. &amp;lt;code&amp;gt;OSentry.$init&amp;lt;/code&amp;gt; erwartet eine DSN, aus der Public Key, Host und Project ID gelesen werden können.&lt;br /&gt;
&lt;br /&gt;
Nach dem Setzen der DSN sollten in der [[#Demo Library|Demo-Library]] folgende Felder gefüllt sein:&lt;br /&gt;
&lt;br /&gt;
* Host&lt;br /&gt;
* Public Key&lt;br /&gt;
* Project ID&lt;br /&gt;
&lt;br /&gt;
=== Netzwerk oder Proxy blockiert den Request ===&lt;br /&gt;
&lt;br /&gt;
Wenn die Anwendung keinen direkten Zugriff auf Sentry hat, setze einen Proxy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.iOSentry.$setProxy(&#039;proxy.example.local&#039;,&#039;8080&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Intern wird der Proxy vor dem HTTP Request gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
If not(isclear(iProxyHost))&amp;amp;not(isclear(iProxyPort))&lt;br /&gt;
	HTTPSetProxyServer (iProxyHost,iProxyPort)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Report wird lokal gespeichert ===&lt;br /&gt;
&lt;br /&gt;
Wenn &amp;lt;code&amp;gt;HTTPPost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HTTPSend&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;HTTPRead&amp;lt;/code&amp;gt; fehlschlägt, speichert OSentry den Report lokal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Calculate path as sys(115)&lt;br /&gt;
Calculate filename as con(&#039;Sentryreport_&#039;,$cinst.$getUnixTimestamp(),&#039;.json&#039;)&lt;br /&gt;
Do fOP.$createfile(con(path,filename)) Returns err&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Suche im Omnis-Installationsordner nach Dateien mit dem Namen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Sentryreport_&amp;lt;timestamp&amp;gt;.json&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sentry antwortet nicht mit 200 OK ===&lt;br /&gt;
&lt;br /&gt;
Wenn die HTTP-Antwort kein &amp;lt;code&amp;gt;200 OK&amp;lt;/code&amp;gt; enthält, wird der JSON Report ebenfalls lokal gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPRead (Socket,Buffer) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0|not(pos(&#039;200 OK&#039;,Buffer))&lt;br /&gt;
	# JSON may be corrupted or contains errors -&amp;gt; save json and the buffer as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,Buffer)&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -3&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mögliche Ursachen:&lt;br /&gt;
&lt;br /&gt;
* falsche Project ID&lt;br /&gt;
* falscher Public Key&lt;br /&gt;
* ungültige DSN&lt;br /&gt;
* JSON Payload wird von Sentry abgelehnt&lt;br /&gt;
* Netzwerk-Gateway verändert den Request&lt;br /&gt;
&lt;br /&gt;
=== Tags oder Extras erscheinen beim falschen Event ===&lt;br /&gt;
&lt;br /&gt;
[[#Tags, Extras und User-Kontext|Tags und Extras]] werden für den nächsten Request gesammelt. Nach erfolgreichem Request werden sie gelöscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iTagList.$clear()&lt;br /&gt;
Do iExtraList.$clear()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn ein Request fehlschlägt, wird ebenfalls aufgeräumt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$clearList()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prüfe trotzdem, ob in eigenen Wrapper-Methoden Tags und Extras direkt vor dem passenden Capture-Aufruf gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== User-Kontext zeigt Demo-Daten ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL.$setUser&amp;lt;/code&amp;gt; verwendet im Export feste Testdaten:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte die Methode parametrisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(pUserID,pUserName,pUserEmail)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception Demo-Button funktioniert nicht ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Trigger an SQLException&amp;lt;/code&amp;gt; ist im Export noch nicht implementiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Code need&#039;s to be written&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die produktive Methode für SQL-Fehler ist aber vorhanden. Siehe auch [[#Events erfassen|Events erfassen]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureSQLException(&#039;SQL statement failed&#039;,stat)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Zu viele Events ===&lt;br /&gt;
&lt;br /&gt;
Sentry kann sehr schnell viele Events sammeln. Verwende für produktive Systeme:&lt;br /&gt;
&lt;br /&gt;
* klare Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
* sinnvolle Levels&lt;br /&gt;
* gezielte [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* keine Events in sehr häufigen Schleifen&lt;br /&gt;
* keine rein informativen Debug-Events ohne Nutzen&lt;br /&gt;
&lt;br /&gt;
=== Sensible Daten ===&lt;br /&gt;
&lt;br /&gt;
[[#Stacktrace und Kontext|Stacktrace]], Parameter, Instance Variablen, SQL-Text und [[#Tags, Extras und User-Kontext|Extras]] können sensible Daten enthalten. Prüfe vor produktiver Nutzung:&lt;br /&gt;
&lt;br /&gt;
* Welche Variablen werden übertragen?&lt;br /&gt;
* Enthalten SQL-Statements personenbezogene Daten?&lt;br /&gt;
* Werden Tokens oder Passwörter in Extras geschrieben?&lt;br /&gt;
* Sollen bestimmte Werte maskiert werden?&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Sentry&amp;diff=9531</id>
		<title>Sentry</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Sentry&amp;diff=9531"/>
		<updated>2026-06-12T14:08:18Z</updated>

		<summary type="html">&lt;p&gt;Silvan: /* DSN setzen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- MediaWiki source for page: Sentry --&amp;gt;&lt;br /&gt;
&amp;lt;!-- Upload required files before publishing: Sentry-issue.png, Sentry-stack.png, Sentry-tags.png, Sentry-projects.png, Demo-window.svg, Demo-dsn.svg --&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Überblick ==&lt;br /&gt;
&lt;br /&gt;
OSentry ist ein REST-API-Konnektor von Omnis Studio zu Sentry. Der Konnektor sendet Fehler, Messages, Logs und Laufzeitkontext aus Omnis-Anwendungen an Sentry, damit Probleme in produktiven Systemen sichtbar, gruppierbar und analysierbar werden.&lt;br /&gt;
&lt;br /&gt;
Diese Dokumentation beschreibt die [[#Installation|Installation]], die Nutzung in bestehenden Omnis-Anwendungen, die Definition eigener standardisierter Exception-Typen, die interne Struktur und die [[#Demo Library|Demo-Library]].&lt;br /&gt;
&lt;br /&gt;
=== Kernidee ===&lt;br /&gt;
&lt;br /&gt;
OSentry besteht aus zwei produktiv relevanten Klassen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;: High-Level-Adapter für die Anwendung. Diese Klasse sollte von normalem Applikationscode aufgerufen werden.&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;: Low-Level-Adapter für DSN-Parsing, JSON-Erzeugung, [[#Stacktrace und Kontext|Stacktrace]]-Aufbereitung und HTTP-Kommunikation mit Sentry.&lt;br /&gt;
&lt;br /&gt;
Die Anwendung arbeitet im Normalfall mit &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;. Dadurch bleiben Sentry-spezifische Details zentral gekapselt und neue standardisierte Exception-Typen können als eigene Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Hauptfeatures ===&lt;br /&gt;
&lt;br /&gt;
* Direkte Anbindung von Omnis Studio an Sentry über REST API und DSN&lt;br /&gt;
* Erfassen von Exceptions, Messages, Logs und SQL-Fehlern&lt;br /&gt;
* Unterstützung der Sentry-Level &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
* Automatische Omnis-Kontextinformationen&lt;br /&gt;
* Omnis-[[#Stacktrace und Kontext|Stacktrace]] mit Klassen, Methoden, Zeilen und Variablen&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]] für Filterung und Gruppierung&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]] für zusätzliche Diagnoseinformationen&lt;br /&gt;
* Optionaler [[#Tags, Extras und User-Kontext|User-Kontext]]&lt;br /&gt;
* Proxy-Unterstützung&lt;br /&gt;
* Aktivieren und Deaktivieren der Sentry-Übertragung&lt;br /&gt;
* Lokales Speichern von Reports bei Übertragungsfehlern&lt;br /&gt;
&lt;br /&gt;
=== Weiterführende Links ===&lt;br /&gt;
&lt;br /&gt;
* [https://sentry.io/welcome/ Sentry Website]&lt;br /&gt;
* [https://sentry.io/signup/ Sentry Account erstellen]&lt;br /&gt;
* [https://develop.sentry.dev/self-hosted/ Sentry self-hosted]&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite beschreibt, wie OSentry in eine bestehende Omnis-Anwendung integriert wird.&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* Omnis Studio Anwendung&lt;br /&gt;
* Sentry Account oder self-hosted Sentry Installation&lt;br /&gt;
* Ein Sentry-Projekt mit SDK-Typ &amp;lt;code&amp;gt;Other&amp;lt;/code&amp;gt;&lt;br /&gt;
* Die DSN des Sentry-Projekts&lt;br /&gt;
* Netzwerkzugriff auf Sentry&lt;br /&gt;
&lt;br /&gt;
Die exportierte [[#Demo Library|Demo-Library]] wurde mit Omnis &amp;lt;code&amp;gt;11.1&amp;lt;/code&amp;gt; erstellt.&lt;br /&gt;
&lt;br /&gt;
=== Sentry-Projekt erstellen ===&lt;br /&gt;
&lt;br /&gt;
# In Sentry ein neues Projekt erstellen.&lt;br /&gt;
# Als SDK &amp;lt;code&amp;gt;Other&amp;lt;/code&amp;gt; auswählen.&lt;br /&gt;
# Die DSN des Projekts kopieren.&lt;br /&gt;
&lt;br /&gt;
Die DSN wird beim Initialisieren verwendet. &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; zerlegt sie intern in Public Key, Host und Project ID.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-projects.png|900px|Sentry Projektübersicht]]&lt;br /&gt;
&lt;br /&gt;
=== Klassen kopieren ===&lt;br /&gt;
&lt;br /&gt;
Kopiere die folgenden Klassen in deine bestehende Omnis-Library:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Demo-spezifischen Klassen sind für die produktive Integration nicht erforderlich. Damit sind die übrigen Klassen der Demo-Library gemeint, zum Beispiel &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt;. Diese Klassen dienen nur dazu, die [[#Demo Library|Demo-Library]] mit Fenster, SQLite-Testdaten und Beispielaufrufen auszuführen.&lt;br /&gt;
&lt;br /&gt;
=== Task Variable anlegen ===&lt;br /&gt;
&lt;br /&gt;
Lege in deiner Startup Task eine Task Variable an:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Name !! Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; sollte als global erreichbarer Singleton der Anwendung verwendet werden. In Omnis ist dafür eine Task Variable sinnvoll, weil sie von Fenstern, Objektklassen und zentralen Error-Handlern aus konsistent erreichbar ist. Dadurch gibt es genau eine aktive Sentry-Konfiguration mit einer DSN, einem Status, optionalen Proxy-Daten und gemeinsamen Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im [[#Demo Library|Demo-Projekt]] ist diese Variable in &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; definiert.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung im Startup Task ===&lt;br /&gt;
&lt;br /&gt;
Initialisiere &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; beim Start deiner Anwendung mit der DSN deines Sentry-Projekts:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;&amp;lt;DSN&amp;gt;&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die [[#Demo Library|Demo-Library]] ruft im Startup Task ebenfalls die Initialisierung auf. Quelle: &amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init Sentry on lbs startup&lt;br /&gt;
Do tSentry.$init()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In einer produktiven Anwendung sollte die DSN explizit oder aus einer Konfiguration übergeben werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;https://PUBLIC_KEY@sentry.io/PROJECT_ID&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; Speichere die DSN in einer Datenbank, einer Konfigurationstabelle oder einem Config File. So kann sie pro Kunde, Umgebung oder Installation geändert werden, ohne die Library neu auszuliefern.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Testcall ===&lt;br /&gt;
&lt;br /&gt;
Nach der Initialisierung kann ein erstes Testevent gesendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello World!&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles korrekt eingerichtet ist, erscheint das Event im Sentry-Projekt.&lt;br /&gt;
&lt;br /&gt;
=== Proxy konfigurieren ===&lt;br /&gt;
&lt;br /&gt;
Falls die Anwendung in einem geschützten Netzwerk läuft, kann ein Proxy gesetzt werden. Die Methode befindet sich im Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.iOSentry.$setProxy(&#039;proxy.example.local&#039;,&#039;8080&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die interne Implementierung setzt den Proxy vor dem HTTP-Request:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Configure proxy; needed when sending data out of secured networks&lt;br /&gt;
If not(isclear(iProxyHost))&amp;amp;not(isclear(iProxyPort))&lt;br /&gt;
	HTTPSetProxyServer (iProxyHost,iProxyPort)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sentry aktivieren oder deaktivieren ===&lt;br /&gt;
&lt;br /&gt;
OSentry kann zentral ein- oder ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; Deaktiviere Sentry in der Entwicklungs-Version standardmäßig oder verwende eine separate Entwicklungs-DSN. So landen lokale Tests, Debug-Fehler und absichtlich ausgelöste Exceptions nicht im produktiven Sentry-Projekt.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$setStatus(1)     ## aktiv&lt;br /&gt;
Do tSentry.$setStatus(0)     ## inaktiv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; wird vor dem Senden geprüft:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Check if Sentry is enabled&lt;br /&gt;
If iStatus=0|isclear(iStatus)&lt;br /&gt;
	Quit method 0&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite zeigt die minimale Integration in eine bestehende Omnis-Anwendung.&lt;br /&gt;
&lt;br /&gt;
=== Klassen übernehmen ===&lt;br /&gt;
&lt;br /&gt;
Kopiere &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; in deine Library.&lt;br /&gt;
&lt;br /&gt;
=== Task Variable erstellen ===&lt;br /&gt;
&lt;br /&gt;
In der Startup Task:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Name !! Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sentry initialisieren ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;https://PUBLIC_KEY@sentry.io/PROJECT_ID&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL.$init&amp;lt;/code&amp;gt; delegiert an das Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init of the main sentry object&lt;br /&gt;
Do iOSentry.$init(pDSN)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message senden ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die [[#Demo Library|Demo-Library]] verwendet genau diesen Aufruf im Button &amp;lt;code&amp;gt;Trigger a message&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.message.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exception senden ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== In Sentry prüfen ===&lt;br /&gt;
&lt;br /&gt;
In Sentry sollte anschließend ein neues Event sichtbar sein. Je nach Event-Typ enthält es:&lt;br /&gt;
&lt;br /&gt;
* Message&lt;br /&gt;
* Level&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|User-Kontext]]&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]]&lt;br /&gt;
* Omnis-Kontextinformationen&lt;br /&gt;
&lt;br /&gt;
== Events erfassen ==&lt;br /&gt;
&lt;br /&gt;
OSentryHL ist die empfohlene Einstiegsschicht für Applikationscode. Die Klasse bietet sprechende Methoden für typische Event-Arten und ruft intern &amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
&lt;br /&gt;
=== Message ===&lt;br /&gt;
&lt;br /&gt;
Eine einfache Information wird mit &amp;lt;code&amp;gt;$captureMessage&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello World!&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an Info Message&lt;br /&gt;
Do iOSentry.$captureException(pMessage,3,,&#039;info&#039;,kFalse,,kFalse) Returns code&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Level: &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;&lt;br /&gt;
* Kein [[#Stacktrace und Kontext|Stacktrace]]&lt;br /&gt;
* Kein [[#Tags, Extras und User-Kontext|User Interface]]&lt;br /&gt;
* Geeignet für einfache Statusmeldungen oder technische Hinweise&lt;br /&gt;
&lt;br /&gt;
=== Log ===&lt;br /&gt;
&lt;br /&gt;
Ein Log-Event wird mit &amp;lt;code&amp;gt;$captureLog&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureLog(&#039;Uh oh this is a Log because something went wrong&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a Log Sentry Report&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;Log&#039;,&#039;warning&#039;,1,0,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Level: &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]] aktiv&lt;br /&gt;
* Exception Interface in diesem Wrapper deaktiviert&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|User Interface]] aktiv&lt;br /&gt;
&lt;br /&gt;
=== Generische Exception ===&lt;br /&gt;
&lt;br /&gt;
Eine generische Exception wird mit &amp;lt;code&amp;gt;$captureException&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture a generic Exception&lt;br /&gt;
#Add any custom tags / extras&lt;br /&gt;
Do $cinst.$addTag(&#039;Custom Test Tag&#039;,&#039;Euromnis&#039;)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; || Text, der in Sentry als Message sichtbar ist&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; || Fehlercode oder fachlicher Code&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExcType&amp;lt;/code&amp;gt; || Exception-Typ für Benennung und Gruppierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pLevel&amp;lt;/code&amp;gt; || Sentry-Level&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Gültige Levels:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception ===&lt;br /&gt;
&lt;br /&gt;
SQL-Fehler können mit &amp;lt;code&amp;gt;$captureSQLException&amp;lt;/code&amp;gt; gemeldet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureSQLException(&#039;SQL statement failed&#039;,stat)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Fügt die Datenbank als [[#Tags, Extras und User-Kontext|Tag]] hinzu&lt;br /&gt;
* Fügt SQL-Text als [[#Tags, Extras und User-Kontext|Extra]] hinzu&lt;br /&gt;
* Fügt native Datenbankfehlermeldung als [[#Tags, Extras und User-Kontext|Extra]] hinzu&lt;br /&gt;
* Sendet das Event als &amp;lt;code&amp;gt;SQL-Exception&amp;lt;/code&amp;gt; mit Level &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deprecated Call ===&lt;br /&gt;
&lt;br /&gt;
Veraltete Codepfade können gezielt gemeldet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureDeprecatedCall()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Wrapper eignet sich, um zu erkennen, ob alter Code in produktiven Systemen noch ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
=== Frei konfigurierbares Event ===&lt;br /&gt;
&lt;br /&gt;
Für Sonderfälle gibt es &amp;lt;code&amp;gt;$captureAnything&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureAnything(&#039;Text&#039;,1001,&#039;Custom Type&#039;,&#039;error&#039;,kTrue,kTrue,kTrue)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Capture a generic Sentry Report (max configurability)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Methode bietet maximale Flexibilität. Für wiederkehrende Exception-Typen sollte aber eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; angelegt werden. Siehe [[#Eigene Exceptions standardisieren|04 Eigene Exceptions standardisieren]].&lt;br /&gt;
&lt;br /&gt;
== Eigene Exceptions standardisieren ==&lt;br /&gt;
&lt;br /&gt;
Wenn ein Exception-Typ mehrfach in der Anwendung vorkommt, sollte er nicht überall manuell mit &amp;lt;code&amp;gt;$captureException&amp;lt;/code&amp;gt; aufgebaut werden. Besser ist eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dadurch entsteht eine zentrale, wiederverwendbare Definition für:&lt;br /&gt;
&lt;br /&gt;
* Exception-Typ&lt;br /&gt;
* Sentry-Level&lt;br /&gt;
* Fehlercode&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]]&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]]/[[#Tags, Extras und User-Kontext|User]]/Exception Interface&lt;br /&gt;
&lt;br /&gt;
Die automatisch gesetzten [[#Tags, Extras und User-Kontext|Tags und Extras]] aus &amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; müssen in solchen Wrappern nicht erneut ergänzt werden. Eigene Exception-Methoden setzen nur zusätzliche Werte, die für diesen standardisierten Exception-Typ relevant sind.&lt;br /&gt;
&lt;br /&gt;
=== Warum über OSentryHL? ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ist die Abstraktionsschicht für Applikationscode. Sie kapselt die Details von &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und sorgt dafür, dass Aufrufe in der Anwendung kurz und konsistent bleiben.&lt;br /&gt;
&lt;br /&gt;
Bestehende Beispiele aus &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Empfohlenes Muster ===&lt;br /&gt;
&lt;br /&gt;
Für jeden standardisierten Exception-Typ wird eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; erstellt.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a validation exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Field&#039;,pField)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Invalid Value&#039;,pValue)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,2001,&#039;Validation-Exception&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mögliche Parameter der neuen Methode:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Beispiel !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;Invalid customer number&#039;&amp;lt;/code&amp;gt; || Sentry Message&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pModule&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;Customer&#039;&amp;lt;/code&amp;gt; || Filterbarer Tag&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pField&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;cu_number&#039;&amp;lt;/code&amp;gt; || Diagnoseinformation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pValue&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;ABC&#039;&amp;lt;/code&amp;gt; || Diagnoseinformation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der Applikationscode bleibt dadurch einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureValidationException(&#039;Invalid customer number&#039;,&#039;Customer&#039;,&#039;cu_number&#039;,cu_number)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel: Business Rule Exception ===&lt;br /&gt;
&lt;br /&gt;
Neue Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a business rule violation&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addTag(&#039;Business Rule&#039;,pRuleName)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Details&#039;,pDetails)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aufruf in der Anwendung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureBusinessRuleViolation(&#039;Invoice cannot be posted&#039;,&#039;Invoice&#039;,&#039;PostingAllowed&#039;,&#039;Invoice is missing customer&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel: Integration Exception ===&lt;br /&gt;
&lt;br /&gt;
Neue Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an integration exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Integration&#039;,pSystem)&lt;br /&gt;
Do $cinst.$addTag(&#039;Endpoint&#039;,pEndpoint)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Payload&#039;,pPayload)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Response&#039;,pResponse)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,4001,&#039;Integration-Exception&#039;,&#039;error&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aufruf in der Anwendung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureIntegrationException(&#039;External API request failed&#039;,&#039;ERP&#039;,&#039;/api/customer&#039;,jsonPayload,responseText)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Namenskonventionen ===&lt;br /&gt;
&lt;br /&gt;
Empfehlung für neue Methoden:&lt;br /&gt;
&lt;br /&gt;
* Methodenname beginnt mit &amp;lt;code&amp;gt;$capture&amp;lt;/code&amp;gt;&lt;br /&gt;
* Der fachliche Typ steht im Methodennamen&lt;br /&gt;
* Der Sentry Exception Type ist stabil und ändert sich nicht laufend&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]] sind kurz und filterbar&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]] dürfen länger sein und Diagnoseinformationen enthalten&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureValidationException&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureBusinessRuleViolation&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureIntegrationException&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$capturePermissionViolation&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureConfigurationError&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error Codes ===&lt;br /&gt;
&lt;br /&gt;
Verwende feste Fehlercodes für standardisierte Exception-Typen. Dadurch können Events in Sentry besser gefiltert und wiedererkannt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Code !! Exception Type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Validation-Exception&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Business-Rule-Violation&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Integration-Exception&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;5001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Configuration-Error&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wann nicht standardisieren? ===&lt;br /&gt;
&lt;br /&gt;
Nicht jeder Einzelfall braucht eine eigene Methode. Für einmalige technische Tests oder sehr spezielle Fälle reicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald ein Exception-Typ aber mehrfach vorkommt oder fachlich relevant ist, sollte er als eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
== Tags, Extras und User-Kontext ==&lt;br /&gt;
&lt;br /&gt;
Tags, Extras und User-Kontext reichern Sentry-Events mit zusätzlichen Informationen an. Diese Informationen helfen beim Filtern, Gruppieren und Analysieren.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-tags.png|900px|Sentry Tags und User-Kontext]]&lt;br /&gt;
&lt;br /&gt;
=== Tags ===&lt;br /&gt;
&lt;br /&gt;
Tags sind kurze, filterbare Werte.&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* Datenbank&lt;br /&gt;
* Kunde&lt;br /&gt;
* Modul&lt;br /&gt;
* Umgebung&lt;br /&gt;
* Error Code&lt;br /&gt;
* Omnis-Version&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add a Tag to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addTag(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Adds a tag to the next request processed&lt;br /&gt;
Do iTagList.$add(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$addTag(&#039;Module&#039;,&#039;Invoice&#039;)&lt;br /&gt;
Do tSentry.$addTag(&#039;Customer&#039;,&#039;10001&#039;)&lt;br /&gt;
Do tSentry.$captureException(&#039;Invoice posting failed&#039;,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Extras ===&lt;br /&gt;
&lt;br /&gt;
Extras sind Detailinformationen, die nicht primär zum Filtern gedacht sind.&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* SQL-Text&lt;br /&gt;
* Native Datenbankfehlermeldung&lt;br /&gt;
* Payload&lt;br /&gt;
* Response Body&lt;br /&gt;
* interne IDs&lt;br /&gt;
* zusätzliche Debug-Informationen&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add an Extra to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addExtra(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Adds extra information to the next request being processed&lt;br /&gt;
Do iExtraList.$add(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel aus der SQL Exception:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Automatische Tags ===&lt;br /&gt;
&lt;br /&gt;
Die folgenden Tags werden bei jedem Event automatisch von &amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; ergänzt. Sie müssen bei eigenen Exceptions nicht erneut gesetzt werden. Eigene Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; sollten nur zusätzliche, fachlich oder technisch relevante Tags hinzufügen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; fügt mehrere Tags automatisch hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add static tags&lt;br /&gt;
Do iTagList.$add(&#039;Omnisversion&#039;,sys(1))&lt;br /&gt;
Calculate systemversionRow as systemversion()&lt;br /&gt;
Do iTagList.$add(&#039;Plattform&#039;,con(sys(8),pick(systemversionRow.server,&#039;&#039;,&#039; SRV&#039;)))&lt;br /&gt;
Do iTagList.$add(&#039;OS Version&#039;,con(systemversionRow.major,&#039;.&#039;,systemversionRow.minor,&#039;.&#039;,systemversionRow.build))&lt;br /&gt;
Do iTagList.$add(&#039;error_code&#039;,pErrorCode)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Automatisch gesendete Tags:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tag !! Herkunft !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Omnisversion&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;sys(1)&amp;lt;/code&amp;gt; || Zeigt, mit welcher Omnis-Version das Event erzeugt wurde&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Plattform&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;sys(8)&amp;lt;/code&amp;gt; und Server-Flag aus &amp;lt;code&amp;gt;systemversion()&amp;lt;/code&amp;gt; || Unterscheidet Plattform und Server Runtime&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OS Version&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;systemversionRow.major/minor/build&amp;lt;/code&amp;gt; || Zeigt die Betriebssystemversion&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;error_code&amp;lt;/code&amp;gt; || Parameter &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; || Verbindet das Event mit dem übergebenen Fehlercode&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Beispiel für eine eigene Exception: Der Wrapper muss nicht erneut &amp;lt;code&amp;gt;Omnisversion&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;OS Version&amp;lt;/code&amp;gt; setzen. Er ergänzt nur das, was für diesen Exception-Typ zusätzlich hilfreich ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addTag(&#039;Business Rule&#039;,pRuleName)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Automatische Extras ===&lt;br /&gt;
&lt;br /&gt;
Auch die folgenden Extras werden bei jedem Event automatisch ergänzt. Bei eigenen Exceptions müssen nur zusätzliche Extras gesetzt werden, zum Beispiel ein SQL-Statement, ein Payload oder fachliche Zusatzdaten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; fügt offene Fenster, offene Reports und die aktuelle Printfile hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Static extra 1: All open windows&lt;br /&gt;
Do $root.$iwindows.$makelist($ref.$name) Returns nameList&lt;br /&gt;
For i from 1 to nameList.$linecount step 1&lt;br /&gt;
	Calculate windows as con(windows,&#039;, &#039;,nameList.[i].1)&lt;br /&gt;
End For&lt;br /&gt;
Calculate windows as right(windows,len(windows)-2)&lt;br /&gt;
Do iExtraList.$add(&#039;Open Windows&#039;,windows)&lt;br /&gt;
&lt;br /&gt;
# Static extra 2: All open reports&lt;br /&gt;
Do $root.$ireports.$makelist($ref.$name) Returns nameList&lt;br /&gt;
For i from 1 to nameList.$linecount step 1&lt;br /&gt;
	Calculate reports as con(reports,&#039;, &#039;,nameList.[i].1)&lt;br /&gt;
End For&lt;br /&gt;
Calculate reports as right(reports,len(reports)-2)&lt;br /&gt;
Do iExtraList.$add(&#039;Open Reports&#039;,reports)&lt;br /&gt;
Do iExtraList.$add(&#039;Current Printfile&#039;,$root.$prefs.$printfile)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Automatisch gesendete Extras:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Extra !! Herkunft !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Open Windows&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$iwindows.$makelist($ref.$name)&amp;lt;/code&amp;gt; || Zeigt, welche Fenster im Moment des Events offen waren&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Open Reports&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$ireports.$makelist($ref.$name)&amp;lt;/code&amp;gt; || Zeigt, welche Reports im Moment des Events offen waren&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Current Printfile&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$prefs.$printfile&amp;lt;/code&amp;gt; || Zeigt die aktuell gesetzte Printfile&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Beispiel für zusätzliche Extras in einem eigenen Wrapper:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addExtra(&#039;Payload&#039;,pPayload)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Response&#039;,pResponse)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,4001,&#039;Integration-Exception&#039;,&#039;error&#039;,1,1,1) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== User-Kontext ===&lt;br /&gt;
&lt;br /&gt;
Der User-Kontext ordnet ein Event einem betroffenen Benutzer zu. In Sentry erscheint dadurch ein eigener User-Bereich, und Events können nach Benutzer gefiltert oder gruppiert werden. Das ist besonders hilfreich, wenn ein Fehler nur bei einzelnen Kunden, Arbeitsplätzen oder Benutzerkonten auftritt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; unterstützt drei User-Felder:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feld !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt; || stabile interne Benutzer-ID oder Kundennummer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;username&amp;lt;/code&amp;gt; || lesbarer Benutzername&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;email&amp;lt;/code&amp;gt; || E-Mail-Adresse, falls sie übertragen werden darf&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der User-Kontext wird nur in das Event geschrieben, wenn das User Interface beim Capture-Aufruf aktiviert ist. Die Standardmethode &amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; hat &amp;lt;code&amp;gt;pUserInterface&amp;lt;/code&amp;gt; standardmäßig auf &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt;. Einzelne High-Level-Methoden können das bewusst deaktivieren, zum Beispiel &amp;lt;code&amp;gt;$captureMessage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; kann User-Daten an das Event anhängen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Sets userinformation for the next request being processed&lt;br /&gt;
Calculate iUserID as pID&lt;br /&gt;
Calculate iUserName as pName&lt;br /&gt;
Calculate iUserEmail as pEmail&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das User Interface wird so generiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Create user data row&lt;br /&gt;
Do UserdataRow.$define(id,email,username)&lt;br /&gt;
&lt;br /&gt;
Calculate UserdataRow.id as iUserID&lt;br /&gt;
Calculate UserdataRow.email as iUserEmail&lt;br /&gt;
Calculate UserdataRow.username as iUserName&lt;br /&gt;
&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;user&#039;,&#039;&#039;)&lt;br /&gt;
Do JSON.$setobject(&#039;user&#039;,UserdataRow)&lt;br /&gt;
&lt;br /&gt;
Calculate jsonString as OJSON.$formatjson(JSON.$getjson())&lt;br /&gt;
&lt;br /&gt;
Quit method jsonString&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die aktuelle Demo-Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; verwendet feste Testdaten. Quelle: &amp;lt;code&amp;gt;OSentryHL.$setUser&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Set the User which should be linked to the Sentry Issue&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte diese Methode angepasst und parametrisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(pUserID,pUserName,pUserEmail)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Empfohlen ist, den User nach Login oder beim Wechsel des aktiven Benutzers zentral zu setzen. Bei anonymen oder sensiblen Installationen kann statt Name und E-Mail auch nur eine interne ID oder ein pseudonymisierter Wert verwendet werden.&lt;br /&gt;
&lt;br /&gt;
=== Datenschutz ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #72777d; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Datenschutz:&#039;&#039;&#039; Prüfe vor produktiver Nutzung, welche Daten an Sentry gesendet werden. Besonders kritisch sind personenbezogene Daten, SQL-Statements, Zugangsdaten, Tokens und interne Pfade.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Besonders kritisch sind:&lt;br /&gt;
&lt;br /&gt;
* personenbezogene Daten&lt;br /&gt;
* Kundendaten&lt;br /&gt;
* SQL-Statements mit Werten&lt;br /&gt;
* Zugangsdaten&lt;br /&gt;
* Tokens&lt;br /&gt;
* interne Pfade&lt;br /&gt;
&lt;br /&gt;
Tags und Extras sollten so gestaltet werden, dass sie für die Fehleranalyse hilfreich sind, aber keine unnötigen sensiblen Daten übertragen.&lt;br /&gt;
&lt;br /&gt;
== Stacktrace und Kontext ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; erzeugt einen Omnis-spezifischen Stacktrace und übergibt ihn an Sentry. Dadurch sieht man in Sentry nicht nur eine Fehlermeldung, sondern auch Klassen, Methoden, Zeilen und Variablenkontext. Ergänzende Informationen zu [[#Tags, Extras und User-Kontext|Tags, Extras und User-Kontext]] stehen auf der separaten Kontext-Seite.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-stack.png|900px|Sentry Stacktrace mit Omnis-Kontext]]&lt;br /&gt;
&lt;br /&gt;
=== Stack lesen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateStacktraceInterface&amp;lt;/code&amp;gt; verwendet &amp;lt;code&amp;gt;sys(192)&amp;lt;/code&amp;gt;, um den aktuellen Omnis-Stack zu lesen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Clean up the Stacklist (remove OSentry classes from the stack)&lt;br /&gt;
Do sys(192) Returns sys192List&lt;br /&gt;
For sys192List.$line from 1 to sys192List.$linecount step 1&lt;br /&gt;
	Set reference class to sys192List.classitem&lt;br /&gt;
	If pos(&#039;OSentry&#039;,class.$name)&amp;gt;0|pos(&#039;OSentryHL&#039;,class.$name)&amp;gt;0&lt;br /&gt;
		Do sys192List.[sys192List.$line].$selected.$assign(kTrue)&lt;br /&gt;
	End If&lt;br /&gt;
End For&lt;br /&gt;
Do sys192List.$remove(kListDeleteSelected)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Interne Frames von &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; werden entfernt, damit in Sentry die fachlich relevanten Stellen sichtbar bleiben.&lt;br /&gt;
&lt;br /&gt;
=== SQL-Error Frames entfernen ===&lt;br /&gt;
&lt;br /&gt;
Bestimmte interne SQL-Fehlerframes werden ebenfalls entfernt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Remove some other classes which we do not want to display&lt;br /&gt;
If sys192List.1.method=&#039;$sqlerror&#039;&lt;br /&gt;
	Do sys192List.$remove(1)&lt;br /&gt;
Else If sys192List.1.method=&#039;$statementerror&#039;&lt;br /&gt;
	Do sys192List.$remove(1)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frames erzeugen ===&lt;br /&gt;
&lt;br /&gt;
Für jeden Stack-Eintrag werden Funktion, Zeilennummer und Kontextzeile erzeugt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Loop through every item on the omnis stack&lt;br /&gt;
For sys192List.$line from 1 to sys192List.$linecount step 1&lt;br /&gt;
	Set reference class to sys192List.classitem&lt;br /&gt;
	Calculate className as class.$name&lt;br /&gt;
	&lt;br /&gt;
	# Create the content row&lt;br /&gt;
	Do contentRow.$define(vars,function,pre_context,context_line,lineno,filename,post_context)&lt;br /&gt;
	Calculate contentRow.lineno as sys192List.line&lt;br /&gt;
	Calculate contentRow.filename as testFileName&lt;br /&gt;
	Calculate contentRow.context_line as sys192List.linetext&lt;br /&gt;
	If isclear(sys192List.object)&lt;br /&gt;
		Calculate contentRow.function as con(className,&#039;.&#039;,sys192List.method) ## If it&#039;s a class method&lt;br /&gt;
	Else&lt;br /&gt;
		Calculate contentRow.function as con(className,&#039;.&#039;,sys192List.object,&#039;.&#039;,sys192List.method) ## If it&#039;s a method of an object of a class (e.g. Headedlist)&lt;br /&gt;
	End If&lt;br /&gt;
	Do contentList.$add(contentRow)&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablen aufnehmen ===&lt;br /&gt;
&lt;br /&gt;
Pro Stackframe werden Instance Variablen und Parameter gesammelt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Get all iVars&lt;br /&gt;
Do varList.$define(name,value)&lt;br /&gt;
Set reference class to sys192List.inst&lt;br /&gt;
Do $cinst.$getVars(&#039;ivars&#039;,class) Returns varList&lt;br /&gt;
&lt;br /&gt;
# Get all params&lt;br /&gt;
Calculate paramList as sys192List.params&lt;br /&gt;
For paramList.$line from 1 to paramList.$linecount step 1&lt;br /&gt;
	If not(paramList.value=&#039;(Not empty)&#039;)&lt;br /&gt;
		Do varList.$add(paramList.name,paramList.value)&lt;br /&gt;
	Else&lt;br /&gt;
		Do varList.$add(paramList.name,&#039;(Not empty)&#039;)&lt;br /&gt;
	End If&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pre- und Post-Context ===&lt;br /&gt;
&lt;br /&gt;
OSentry fügt Methodenzeilen vor und nach der aktuellen Zeile hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Pre Context (all method lines before the error occured)&lt;br /&gt;
Set reference method to sys192List.methoditem&lt;br /&gt;
Do precontextList.$define(line)&lt;br /&gt;
For i from 1 to sys192List.line-1 step 1&lt;br /&gt;
	Do precontextList.$add(method.$methodlines.[i].$text)&lt;br /&gt;
End For&lt;br /&gt;
&lt;br /&gt;
# Post Context (all method lines after the error occured&lt;br /&gt;
Do postcontextList.$define(line)&lt;br /&gt;
For i from sys192List.line+1 to method.$methodlines.$count step 1&lt;br /&gt;
	Do postcontextList.$add(method.$methodlines.[i].$text)&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablentypen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$getVars&amp;lt;/code&amp;gt; unterstützt Basisvariablen, Rows und Lists.&lt;br /&gt;
&lt;br /&gt;
Basisvariablen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
If varType=&#039;char&#039;|varType=&#039;boolean&#039;|varType=&#039;integer&#039;|varType=&#039;number&#039;|varType=&#039;date&#039;&lt;br /&gt;
	Calculate varContent as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	Do varList.$add(varName,varContent)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Else If varType=&#039;row&#039;&lt;br /&gt;
	Calculate varRow as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	If varRow.$colcount=0&lt;br /&gt;
		Do varList.$add(varName,&#039;(Empty)&#039;)&lt;br /&gt;
	Else&lt;br /&gt;
		For Z2 from 1 to varRow.$colcount step 1&lt;br /&gt;
			Calculate varContent as con(varContent,varRow.$cols.[Z2].$name,&#039;: &#039;,varRow.[Z2],&#039;, &#039;)&lt;br /&gt;
		End For&lt;br /&gt;
		Do varList.$add(varName,varContent)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lists:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Else If varType=&#039;list&#039;&lt;br /&gt;
	Calculate varListType as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	Calculate varContent as con(&#039;Colcount: &#039;,varListType.$colcount,&#039;, &#039;,&#039;Linecount: &#039;,varListType.$linecount,&#039;, &#039;,&#039;Current Line: &#039;,varListType.$line)&lt;br /&gt;
	If varListType.$linecount=0&amp;amp;varListType.$line=0&amp;amp;varListType.$colcount=0&lt;br /&gt;
		Do varList.$add(varName,&#039;(Empty)&#039;)&lt;br /&gt;
		Calculate varContent as &#039;&#039;&lt;br /&gt;
	Else&lt;br /&gt;
		For Z3 from 1 to varListType.$colcount step 1&lt;br /&gt;
			Calculate colName as varListType.$cols.[Z3].$name&lt;br /&gt;
			Calculate varContent as con(varContent,&#039;  &#039;,colName,&#039;: &#039;,varListType.[colName])&lt;br /&gt;
		End For&lt;br /&gt;
		Do varList.$add(varName,varContent)&lt;br /&gt;
		Calculate varContent as &#039;&#039;&lt;br /&gt;
	End If&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
&lt;br /&gt;
Stacktrace und Variablenkontext sind sehr hilfreich, können aber sensible Daten enthalten. Vor produktiver Nutzung sollte geprüft werden, ob bestimmte Variablen anonymisiert oder ausgeschlossen werden müssen.&lt;br /&gt;
&lt;br /&gt;
== Interne Architektur ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite beschreibt die produktiv relevanten Klassen &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Klassenübersicht ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Rolle&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; || High-Level-Adapter für Applikationscode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; || Low-Level-Adapter für JSON, [[#Stacktrace und Kontext|Stacktrace]] und HTTP&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Startup und Beispiel für Initialisierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Code für [[#Stacktrace und Kontext|Stacktrace]]-Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-DB Initialisierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt; || SQLite Session für [[#Demo Library|Demo]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Empfohlener Aufrufweg ===&lt;br /&gt;
&lt;br /&gt;
Applikationscode sollte &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; verwenden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; delegiert anschließend an &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ablauf eines Events ===&lt;br /&gt;
&lt;br /&gt;
# Applikationscode ruft Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; fügt bei Bedarf [[#Tags, Extras und User-Kontext|Tags und Extras]] hinzu.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ruft &amp;lt;code&amp;gt;iOSentry.$captureException(...)&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; prüft, ob Sentry aktiv ist.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; erzeugt JSON.&lt;br /&gt;
# [[#Stacktrace und Kontext|Stacktrace]], Exception Interface und [[#Tags, Extras und User-Kontext|User Interface]] werden optional ergänzt.&lt;br /&gt;
# HTTP Header und Sentry Auth Header werden erstellt.&lt;br /&gt;
# JSON wird per HTTPS an Sentry gesendet.&lt;br /&gt;
# Bei Erfolg werden [[#Tags, Extras und User-Kontext|Tags und Extras]] geleert.&lt;br /&gt;
# Bei Fehler wird der JSON Report lokal gespeichert.&lt;br /&gt;
&lt;br /&gt;
=== DSN Parsing ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$init&amp;lt;/code&amp;gt; zerlegt die DSN:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Parse the DSN into Public Key, Host and Project ID&lt;br /&gt;
If len(pDSN)&amp;gt;5&lt;br /&gt;
	Calculate iDSN as pDSN&lt;br /&gt;
	Calculate part1 as strtok(&#039;iDSN&#039;,&#039;@&#039;)&lt;br /&gt;
	Calculate iProtocol as strtok(&#039;part1&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iProtocol as left(iProtocol,len(iProtocol)-1)&lt;br /&gt;
	Do strtok(&#039;part1&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iPubKey as strtok(&#039;part1&#039;,&#039;:&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Calculate iHost as strtok(&#039;iDSN&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iProID as iDSN&lt;br /&gt;
	&lt;br /&gt;
	#Save the values for the next startup&lt;br /&gt;
	Calculate $cclass.$ivardefs.iPubKey.$objinitval as con(&#039;&amp;quot;&#039;,iPubKey,&#039;&amp;quot;&#039;)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iHost.$objinitval as con(&#039;&amp;quot;&#039;,iHost,&#039;&amp;quot;&#039;)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iProID.$objinitval as con(&#039;&amp;quot;&#039;,iProID,&#039;&amp;quot;&#039;)&lt;br /&gt;
End If&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== JSON-Erzeugung ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; ist die zentrale Methode für den Payload. Sie setzt unter anderem:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;event_id&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;logger&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;platform&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;culprit&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;timestamp&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sdk&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;message&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;level&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;tags&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;extra&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;exception&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;stacktrace&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auszug:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add all required fields (those are required from the API)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;event_id&#039;,$cinst.$generateUUID()) ## auto generated UUID 4&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;logger&#039;,logger)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;platform&#039;,platform)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;culprit&#039;,culprit)&lt;br /&gt;
#Do JSON.$addmember(&#039;&#039;,&#039;release&#039;,release)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;timestamp&#039;,timestamp)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;sdk&#039;,&#039;&#039;)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;message&#039;,pErrorText)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;level&#039;,pLevel)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;tags&#039;,&#039;&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== HTTP-Kommunikation ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; sendet den erzeugten JSON-Payload an Sentry:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Generate HTTP Auth header&lt;br /&gt;
Begin text block&lt;br /&gt;
Text:Sentry sentry_version=7,&lt;br /&gt;
Text:sentry_timestamp=[$cinst.$getUnixTimestamp()],&lt;br /&gt;
Text:sentry_key=[iPubKey],&lt;br /&gt;
Text:sentry_client=omnis/1.0&lt;br /&gt;
End text block&lt;br /&gt;
Get text block auth&lt;br /&gt;
&lt;br /&gt;
#Generate header list&lt;br /&gt;
Calculate Host as &#039;sentry.io&#039;&lt;br /&gt;
Calculate Url as con(&#039;/api/&#039;,iProID,&#039;/store/&#039;)&lt;br /&gt;
Do HdrList.$define(wert,name)&lt;br /&gt;
Do HdrList.$add(&#039;User-Agent&#039;,&#039;omnis/1.0&#039;)&lt;br /&gt;
Do HdrList.$add(&#039;Content-Type&#039;,&#039;application/json&#039;)&lt;br /&gt;
Do HdrList.$add(&#039;Content-Length&#039;,binlength(json))&lt;br /&gt;
Do HdrList.$add(&#039;X-Sentry-Auth&#039;,auth)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anschließend wird der Request über &amp;lt;code&amp;gt;HTTPPost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HTTPSend&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;HTTPRead&amp;lt;/code&amp;gt; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
=== Fehlerbehandlung beim Senden ===&lt;br /&gt;
&lt;br /&gt;
Wenn der Socket nicht geöffnet werden kann:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPPost (Host,Url,,HdrList,443,kTrue,kTrue) Returns Socket&lt;br /&gt;
If Socket&amp;lt;0&lt;br /&gt;
	#Error when opening connection -&amp;gt; save json as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,con(&#039;Error &#039;,Socket,&#039; when performing HTTPPost&#039;))&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -1&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn das Senden fehlschlägt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPSend (Socket,json) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0&lt;br /&gt;
	# Error while sending data -&amp;gt; save json as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,con(&#039;Erorr &#039;,byteCount,&#039; when performing HTTPSend&#039;))&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -2&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn die Antwort nicht erfolgreich ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPRead (Socket,Buffer) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0|not(pos(&#039;200 OK&#039;,Buffer))&lt;br /&gt;
	# JSON may be corrupted or contains errors -&amp;gt; save json and the buffer as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,Buffer)&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -3&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Lokales Speichern ===&lt;br /&gt;
&lt;br /&gt;
Bei Fehlern wird der JSON Report lokal im Omnis-Installationsordner gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Writes the json and the http buffer to a file in the omnis installation folder&lt;br /&gt;
Calculate path as sys(115)&lt;br /&gt;
Calculate filename as con(&#039;Sentryreport_&#039;,$cinst.$getUnixTimestamp(),&#039;.json&#039;)&lt;br /&gt;
Do fOP.$createfile(con(path,filename)) Returns err&lt;br /&gt;
Do fOP.$writecharacter(kUniTypeUTF8,pJSON) Returns err&lt;br /&gt;
If not(isclear(pBuffer))&lt;br /&gt;
	Do fOP.$writecharacter(kUniTypeUTF8,con(kCr,pBuffer),kTrue) Returns err&lt;br /&gt;
End If&lt;br /&gt;
Do fOP.$closefile()&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cleanup ===&lt;br /&gt;
&lt;br /&gt;
Nach erfolgreichem Senden werden [[#Tags, Extras und User-Kontext|Tags und Extras]] gelöscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Clears all extras and tags =&amp;gt; to be used after a sentry request has successfully been sent&lt;br /&gt;
Do iTagList.$clear()&lt;br /&gt;
Do iExtraList.$clear()&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Demo Library ==&lt;br /&gt;
&lt;br /&gt;
Die Demo-Library zeigt, wie &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; initialisiert wird und wie verschiedene [[#Events erfassen|Event-Typen]] aus einer Omnis-Oberfläche heraus an Sentry gesendet werden.&lt;br /&gt;
&lt;br /&gt;
=== Bestandteile ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; || Initialisiert Sentry, SQLite und öffnet das Demo-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; || Demo-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt; || Erzeugt Demo-Stack für Exception&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; || Erstellt SQLite-Demo-Datenbank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt; || SQLite Session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; || Low-Level-Sentry-Adapter&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; || High-Level-Sentry-Adapter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt; initialisiert Sentry, baut eine SQLite Session auf und öffnet das Demo-Fenster. Quelle: &amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init Sentry on lbs startup&lt;br /&gt;
Do tSentry.$init()&lt;br /&gt;
&lt;br /&gt;
#SQLite Session init&lt;br /&gt;
Do $objects.OSLSession.$newref() Returns tOSLSession&lt;br /&gt;
#Calculate tOSLSession.$opencreate as kTrue&lt;br /&gt;
Calculate workingDir as tODatabaseHandler.$getWorkingDir()&lt;br /&gt;
Do con(workingDir,&#039;Sentry_Test.db&#039;) Returns dbLocation&lt;br /&gt;
Do tOSLSession.$logon(dbLocation,&#039;&#039;,&#039;&#039;,&#039;slsession&#039;) Returns #F&lt;br /&gt;
&lt;br /&gt;
#Open Test Window&lt;br /&gt;
Do $windows.FSY_Demo.$openonce(&#039;*&#039;)&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Demo-Fenster ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; enthält folgende Bereiche:&lt;br /&gt;
&lt;br /&gt;
* DSN Configuration&lt;br /&gt;
* DB Status&lt;br /&gt;
* Actions&lt;br /&gt;
&lt;br /&gt;
Wichtige Felder:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feld !! Datenanbindung&lt;br /&gt;
|-&lt;br /&gt;
| DSN || &amp;lt;code&amp;gt;iDSN&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Host || &amp;lt;code&amp;gt;tSentry.iOSentry.iHost&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Public Key || &amp;lt;code&amp;gt;tSentry.iOSentry.iPubKey&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Project ID || &amp;lt;code&amp;gt;tSentry.iOSentry.iProID&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| DB Status || &amp;lt;code&amp;gt;iCurrentDBStatus&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Datei:Demo-window.png|850px|Demo-Fenster der OSentry Library]]&lt;br /&gt;
&lt;br /&gt;
=== DSN setzen ===&lt;br /&gt;
&lt;br /&gt;
Die DSN wird im Feld &amp;lt;code&amp;gt;iDSN&amp;lt;/code&amp;gt; erfasst. Der Button &amp;lt;code&amp;gt;Set DSN&amp;lt;/code&amp;gt; ruft anschließend &amp;lt;code&amp;gt;tSentry.$init(iDSN)&amp;lt;/code&amp;gt; auf. Nach dem Setzen werden Public Key, Host und Project ID aus der DSN gelesen und in den darunterliegenden Feldern angezeigt.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Demo-dsn.png|850px|DSN-Konfiguration im Demo-Fenster]]&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Set DSN&amp;lt;/code&amp;gt; initialisiert Sentry mit der eingegebenen DSN. Quelle: &amp;lt;code&amp;gt;FSY_Demo.setDSN.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$init(iDSN)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iDSN.$objinitval as con(kSq,iDSN,kSq)&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$showmessage(&#039;DSN set and Sentry initialized!&#039;,&#039;Info&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$redraw()&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== DB Status anzeigen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FSY_Demo.$displayDBState&amp;lt;/code&amp;gt; zeigt, ob die SQLite Session verbunden ist. Quelle: &amp;lt;code&amp;gt;FSY_Demo.$displayDBState&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tOSLSession.$state Returns dbState&lt;br /&gt;
If dbState=&#039;kSessionStateLoggedOff&#039;&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Logged Off&#039;&lt;br /&gt;
Else If dbState=&#039;kSessionStateLoggedOn&#039;&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Logged On&#039;&lt;br /&gt;
Else&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Unkown DB State&#039;&lt;br /&gt;
End If&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$redraw()&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Demo-Datenbank erstellen ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Create Database&amp;lt;/code&amp;gt; ruft &amp;lt;code&amp;gt;ODatabaseHandler.$DBFirstInit&amp;lt;/code&amp;gt; auf. Quelle: &amp;lt;code&amp;gt;FSY_Demo.createDB.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Setup the DB&lt;br /&gt;
	Do tODatabaseHandler.$DBFirstInit() Returns err&lt;br /&gt;
	If err=0&lt;br /&gt;
		Do $cinst.$showmessage(&#039;DB successfully created!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Else&lt;br /&gt;
		Do $cinst.$showmessage(&#039;Error while creating the DB. Make sure that the DB does not already exist.&#039;,&#039;Info&#039;)&lt;br /&gt;
	End If&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$displayDBState()&lt;br /&gt;
	&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Datenbank wird im Arbeitsverzeichnis der Library angelegt. Quelle: &amp;lt;code&amp;gt;ODatabaseHandler.$getWorkingDir&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Quit method con(FileOps.$parentdir($clib.$pathname),pathsep())&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Demo-DB enthält unter anderem:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;dperson&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;drelease&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;dvcs&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a message&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.message.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Log auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a log&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.log.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureLog(&#039;Uh oh this is a Log because something went wrong&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exception auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger an exception&amp;lt;/code&amp;gt; bereitet eine Row und eine List vor und ruft anschließend &amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt; auf. Quelle: &amp;lt;code&amp;gt;FSY_Demo.exception.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do iDummyRow.$define(id,name)&lt;br /&gt;
	Calculate iDummyRow.id as 22&lt;br /&gt;
	Calculate iDummyRow.name as &#039;Tom&#039;&lt;br /&gt;
	&lt;br /&gt;
	Do iDummyList.$define(id,weekday)&lt;br /&gt;
	Do iDummyList.$add(1,&#039;Monday&#039;)&lt;br /&gt;
	Do iDummyList.$add(2,&#039;Tuesday&#039;)&lt;br /&gt;
	Do iDummyList.$add(3,&#039;Wednesday&#039;)&lt;br /&gt;
	Do iDummyList.$add(4,&#039;Thursday&#039;)&lt;br /&gt;
	Do iDummyList.$add(5,&#039;Friday&#039;)&lt;br /&gt;
	Do iDummyList.$add(6,&#039;Saturday&#039;)&lt;br /&gt;
	Do iDummyList.$add(7,&#039;Sunday&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Calculate iDummyList.$line as 5&lt;br /&gt;
	&lt;br /&gt;
	Do iODummy.$dummyMethod(&#039;Important Value&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt; sendet die Exception. Quelle: &amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#In here is some logic&lt;br /&gt;
#This logic would produce an error&lt;br /&gt;
#We send all this information to Sentry&lt;br /&gt;
&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&lt;br /&gt;
Quit method 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deprecated Call auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a deprecated call&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.deprecatedCall.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureDeprecatedCall()&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception Button ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Trigger an SQLException&amp;lt;/code&amp;gt; ist im Export vorhanden, enthält aber noch keinen fertigen Demo-Code. Quelle: &amp;lt;code&amp;gt;FSY_Demo.sqlException.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Code need&#039;s to be written&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Dokumentation der SQL-Erfassung siehe [[#Events erfassen|03 Events erfassen]].&lt;br /&gt;
&lt;br /&gt;
== API Reference ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite dokumentiert die produktiv relevanten Methoden von &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== OSentryHL ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ist die empfohlene Klasse für Applikationscode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$init(pDSN)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Initialisiert das interne &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;-Objekt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init of the main sentry object&lt;br /&gt;
Do iOSentry.$init(pDSN)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureMessage(pMessage)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet eine einfache Info-Message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an Info Message&lt;br /&gt;
Do iOSentry.$captureException(pMessage,3,,&#039;info&#039;,kFalse,,kFalse) Returns code&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureException(pErrorText,pErrorCode,pExcType,pLevel)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet eine generische Exception.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture a generic Exception&lt;br /&gt;
#Add any custom tags / extras&lt;br /&gt;
Do $cinst.$addTag(&#039;Custom Test Tag&#039;,&#039;Euromnis&#039;)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureAnything(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet ein frei konfigurierbares Event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Capture a generic Sentry Report (max configurability)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hinweis: Der Parameter ist im Export als &amp;lt;code&amp;gt;pStacktraveInterface&amp;lt;/code&amp;gt; geschrieben.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureLog(pErrorText)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet ein Log-Event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a Log Sentry Report&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;Log&#039;,&#039;warning&#039;,1,0,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureDeprecatedCall()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Meldet die Ausführung eines veralteten Codepfads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureSQLException(pErrorText,pStat)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Meldet einen SQL-Fehler mit SQL-Text und nativer Datenbankfehlermeldung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addTag(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt einen Tag für das nächste Event hinzu.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add a Tag to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addTag(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addExtra(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt ein Extra für das nächste Event hinzu.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add an Extra to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addExtra(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setStatus(pStatus)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Aktiviert oder deaktiviert Sentry.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Toggels Sentry on or off&lt;br /&gt;
Do iOSentry.$setStatus(pStatus)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setUser()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt im Export feste [[#Demo Library|Demo]]-Userdaten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Set the User which should be linked to the Sentry Issue&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte diese Methode parametrisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== OSentry ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; ist die Low-Level-Klasse für Payload-Erzeugung und Versand.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$init(pDSN)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parst die DSN in Protokoll, Public Key, Host und Project ID.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraceInterface,pUserInterface,pExceptionInterface)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt JSON, sendet es an Sentry und behandelt Fehlerfälle.&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Default !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; ||  || Message&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; ||  || Fehlercode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExcType&amp;lt;/code&amp;gt; ||  || Exception-Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pLevel&amp;lt;/code&amp;gt; ||  || &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pStacktraceInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || [[#Stacktrace und Kontext|Stacktrace]] senden&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pUserInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || [[#Tags, Extras und User-Kontext|User-Kontext]] senden&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExceptionInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || Exception Interface senden&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateJson(...)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den Sentry JSON Payload als Binary.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateStacktraceInterface(pCulprit)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den Omnis-[[#Stacktrace und Kontext|Stacktrace]] inklusive Variablen und Kontextzeilen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateExceptionInterface(pType,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt das Sentry Exception Interface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Generate Row to store in the JSON&lt;br /&gt;
Do exceptionRow.$define(type,value,stacktrace)&lt;br /&gt;
Calculate exceptionRow.type as pType&lt;br /&gt;
Calculate exceptionRow.value as pValue&lt;br /&gt;
Calculate exceptionRow.stacktrace as &#039;sentry.interfaces.stacktrace&#039; ## Tells the exception interface that a stacktrace is passed aswell&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateUserInterface()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den [[#Tags, Extras und User-Kontext|User-Kontext]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addTag(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt einen Tag zur internen Tag-Liste hinzu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addExtra(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt ein Extra zur internen Extra-Liste hinzu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$clearList()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Leert [[#Tags, Extras und User-Kontext|Tags und Extras]] nach einem Request.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setUserData(pID,pName,pEmail)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt Userdaten für den nächsten Request.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setProxy(pProxyHost,pProxyPort)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt Proxy-Informationen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setStatus(pStatus)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt den Sentry-Status.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Toggels Sentry Reports on or off&lt;br /&gt;
Calculate iStatus as pStatus&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$writeJSON(pJSON,pBuffer)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Schreibt fehlgeschlagene Reports lokal in eine Datei.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$getUnixTimestamp()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Gibt den aktuellen UNIX Timestamp zurück.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateUUID()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt eine UUID für die Sentry Event ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Genereates a UUID for the issue id&lt;br /&gt;
Quit method OW3.$makeuuid(kFalse)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Es erscheinen keine Events in Sentry ===&lt;br /&gt;
&lt;br /&gt;
Prüfe zuerst, ob Sentry aktiv ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$setStatus(1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; beendet sich sofort, wenn der Status &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; oder leer ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Check if Sentry is enabled&lt;br /&gt;
If iStatus=0|isclear(iStatus)&lt;br /&gt;
	Quit method 0&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Die DSN ist falsch ===&lt;br /&gt;
&lt;br /&gt;
Prüfe, ob die DSN korrekt aus Sentry kopiert wurde. &amp;lt;code&amp;gt;OSentry.$init&amp;lt;/code&amp;gt; erwartet eine DSN, aus der Public Key, Host und Project ID gelesen werden können.&lt;br /&gt;
&lt;br /&gt;
Nach dem Setzen der DSN sollten in der [[#Demo Library|Demo-Library]] folgende Felder gefüllt sein:&lt;br /&gt;
&lt;br /&gt;
* Host&lt;br /&gt;
* Public Key&lt;br /&gt;
* Project ID&lt;br /&gt;
&lt;br /&gt;
=== Netzwerk oder Proxy blockiert den Request ===&lt;br /&gt;
&lt;br /&gt;
Wenn die Anwendung keinen direkten Zugriff auf Sentry hat, setze einen Proxy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.iOSentry.$setProxy(&#039;proxy.example.local&#039;,&#039;8080&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Intern wird der Proxy vor dem HTTP Request gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
If not(isclear(iProxyHost))&amp;amp;not(isclear(iProxyPort))&lt;br /&gt;
	HTTPSetProxyServer (iProxyHost,iProxyPort)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Report wird lokal gespeichert ===&lt;br /&gt;
&lt;br /&gt;
Wenn &amp;lt;code&amp;gt;HTTPPost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HTTPSend&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;HTTPRead&amp;lt;/code&amp;gt; fehlschlägt, speichert OSentry den Report lokal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Calculate path as sys(115)&lt;br /&gt;
Calculate filename as con(&#039;Sentryreport_&#039;,$cinst.$getUnixTimestamp(),&#039;.json&#039;)&lt;br /&gt;
Do fOP.$createfile(con(path,filename)) Returns err&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Suche im Omnis-Installationsordner nach Dateien mit dem Namen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Sentryreport_&amp;lt;timestamp&amp;gt;.json&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sentry antwortet nicht mit 200 OK ===&lt;br /&gt;
&lt;br /&gt;
Wenn die HTTP-Antwort kein &amp;lt;code&amp;gt;200 OK&amp;lt;/code&amp;gt; enthält, wird der JSON Report ebenfalls lokal gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPRead (Socket,Buffer) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0|not(pos(&#039;200 OK&#039;,Buffer))&lt;br /&gt;
	# JSON may be corrupted or contains errors -&amp;gt; save json and the buffer as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,Buffer)&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -3&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mögliche Ursachen:&lt;br /&gt;
&lt;br /&gt;
* falsche Project ID&lt;br /&gt;
* falscher Public Key&lt;br /&gt;
* ungültige DSN&lt;br /&gt;
* JSON Payload wird von Sentry abgelehnt&lt;br /&gt;
* Netzwerk-Gateway verändert den Request&lt;br /&gt;
&lt;br /&gt;
=== Tags oder Extras erscheinen beim falschen Event ===&lt;br /&gt;
&lt;br /&gt;
[[#Tags, Extras und User-Kontext|Tags und Extras]] werden für den nächsten Request gesammelt. Nach erfolgreichem Request werden sie gelöscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iTagList.$clear()&lt;br /&gt;
Do iExtraList.$clear()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn ein Request fehlschlägt, wird ebenfalls aufgeräumt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$clearList()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prüfe trotzdem, ob in eigenen Wrapper-Methoden Tags und Extras direkt vor dem passenden Capture-Aufruf gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== User-Kontext zeigt Demo-Daten ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL.$setUser&amp;lt;/code&amp;gt; verwendet im Export feste Testdaten:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte die Methode parametrisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(pUserID,pUserName,pUserEmail)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception Demo-Button funktioniert nicht ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Trigger an SQLException&amp;lt;/code&amp;gt; ist im Export noch nicht implementiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Code need&#039;s to be written&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die produktive Methode für SQL-Fehler ist aber vorhanden. Siehe auch [[#Events erfassen|Events erfassen]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureSQLException(&#039;SQL statement failed&#039;,stat)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Zu viele Events ===&lt;br /&gt;
&lt;br /&gt;
Sentry kann sehr schnell viele Events sammeln. Verwende für produktive Systeme:&lt;br /&gt;
&lt;br /&gt;
* klare Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
* sinnvolle Levels&lt;br /&gt;
* gezielte [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* keine Events in sehr häufigen Schleifen&lt;br /&gt;
* keine rein informativen Debug-Events ohne Nutzen&lt;br /&gt;
&lt;br /&gt;
=== Sensible Daten ===&lt;br /&gt;
&lt;br /&gt;
[[#Stacktrace und Kontext|Stacktrace]], Parameter, Instance Variablen, SQL-Text und [[#Tags, Extras und User-Kontext|Extras]] können sensible Daten enthalten. Prüfe vor produktiver Nutzung:&lt;br /&gt;
&lt;br /&gt;
* Welche Variablen werden übertragen?&lt;br /&gt;
* Enthalten SQL-Statements personenbezogene Daten?&lt;br /&gt;
* Werden Tokens oder Passwörter in Extras geschrieben?&lt;br /&gt;
* Sollen bestimmte Werte maskiert werden?&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Sentry&amp;diff=9530</id>
		<title>Sentry</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Sentry&amp;diff=9530"/>
		<updated>2026-06-12T14:07:58Z</updated>

		<summary type="html">&lt;p&gt;Silvan: /* Demo-Fenster */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- MediaWiki source for page: Sentry --&amp;gt;&lt;br /&gt;
&amp;lt;!-- Upload required files before publishing: Sentry-issue.png, Sentry-stack.png, Sentry-tags.png, Sentry-projects.png, Demo-window.svg, Demo-dsn.svg --&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Überblick ==&lt;br /&gt;
&lt;br /&gt;
OSentry ist ein REST-API-Konnektor von Omnis Studio zu Sentry. Der Konnektor sendet Fehler, Messages, Logs und Laufzeitkontext aus Omnis-Anwendungen an Sentry, damit Probleme in produktiven Systemen sichtbar, gruppierbar und analysierbar werden.&lt;br /&gt;
&lt;br /&gt;
Diese Dokumentation beschreibt die [[#Installation|Installation]], die Nutzung in bestehenden Omnis-Anwendungen, die Definition eigener standardisierter Exception-Typen, die interne Struktur und die [[#Demo Library|Demo-Library]].&lt;br /&gt;
&lt;br /&gt;
=== Kernidee ===&lt;br /&gt;
&lt;br /&gt;
OSentry besteht aus zwei produktiv relevanten Klassen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;: High-Level-Adapter für die Anwendung. Diese Klasse sollte von normalem Applikationscode aufgerufen werden.&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;: Low-Level-Adapter für DSN-Parsing, JSON-Erzeugung, [[#Stacktrace und Kontext|Stacktrace]]-Aufbereitung und HTTP-Kommunikation mit Sentry.&lt;br /&gt;
&lt;br /&gt;
Die Anwendung arbeitet im Normalfall mit &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;. Dadurch bleiben Sentry-spezifische Details zentral gekapselt und neue standardisierte Exception-Typen können als eigene Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Hauptfeatures ===&lt;br /&gt;
&lt;br /&gt;
* Direkte Anbindung von Omnis Studio an Sentry über REST API und DSN&lt;br /&gt;
* Erfassen von Exceptions, Messages, Logs und SQL-Fehlern&lt;br /&gt;
* Unterstützung der Sentry-Level &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
* Automatische Omnis-Kontextinformationen&lt;br /&gt;
* Omnis-[[#Stacktrace und Kontext|Stacktrace]] mit Klassen, Methoden, Zeilen und Variablen&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]] für Filterung und Gruppierung&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]] für zusätzliche Diagnoseinformationen&lt;br /&gt;
* Optionaler [[#Tags, Extras und User-Kontext|User-Kontext]]&lt;br /&gt;
* Proxy-Unterstützung&lt;br /&gt;
* Aktivieren und Deaktivieren der Sentry-Übertragung&lt;br /&gt;
* Lokales Speichern von Reports bei Übertragungsfehlern&lt;br /&gt;
&lt;br /&gt;
=== Weiterführende Links ===&lt;br /&gt;
&lt;br /&gt;
* [https://sentry.io/welcome/ Sentry Website]&lt;br /&gt;
* [https://sentry.io/signup/ Sentry Account erstellen]&lt;br /&gt;
* [https://develop.sentry.dev/self-hosted/ Sentry self-hosted]&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite beschreibt, wie OSentry in eine bestehende Omnis-Anwendung integriert wird.&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* Omnis Studio Anwendung&lt;br /&gt;
* Sentry Account oder self-hosted Sentry Installation&lt;br /&gt;
* Ein Sentry-Projekt mit SDK-Typ &amp;lt;code&amp;gt;Other&amp;lt;/code&amp;gt;&lt;br /&gt;
* Die DSN des Sentry-Projekts&lt;br /&gt;
* Netzwerkzugriff auf Sentry&lt;br /&gt;
&lt;br /&gt;
Die exportierte [[#Demo Library|Demo-Library]] wurde mit Omnis &amp;lt;code&amp;gt;11.1&amp;lt;/code&amp;gt; erstellt.&lt;br /&gt;
&lt;br /&gt;
=== Sentry-Projekt erstellen ===&lt;br /&gt;
&lt;br /&gt;
# In Sentry ein neues Projekt erstellen.&lt;br /&gt;
# Als SDK &amp;lt;code&amp;gt;Other&amp;lt;/code&amp;gt; auswählen.&lt;br /&gt;
# Die DSN des Projekts kopieren.&lt;br /&gt;
&lt;br /&gt;
Die DSN wird beim Initialisieren verwendet. &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; zerlegt sie intern in Public Key, Host und Project ID.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-projects.png|900px|Sentry Projektübersicht]]&lt;br /&gt;
&lt;br /&gt;
=== Klassen kopieren ===&lt;br /&gt;
&lt;br /&gt;
Kopiere die folgenden Klassen in deine bestehende Omnis-Library:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Demo-spezifischen Klassen sind für die produktive Integration nicht erforderlich. Damit sind die übrigen Klassen der Demo-Library gemeint, zum Beispiel &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt;. Diese Klassen dienen nur dazu, die [[#Demo Library|Demo-Library]] mit Fenster, SQLite-Testdaten und Beispielaufrufen auszuführen.&lt;br /&gt;
&lt;br /&gt;
=== Task Variable anlegen ===&lt;br /&gt;
&lt;br /&gt;
Lege in deiner Startup Task eine Task Variable an:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Name !! Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; sollte als global erreichbarer Singleton der Anwendung verwendet werden. In Omnis ist dafür eine Task Variable sinnvoll, weil sie von Fenstern, Objektklassen und zentralen Error-Handlern aus konsistent erreichbar ist. Dadurch gibt es genau eine aktive Sentry-Konfiguration mit einer DSN, einem Status, optionalen Proxy-Daten und gemeinsamen Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im [[#Demo Library|Demo-Projekt]] ist diese Variable in &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; definiert.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung im Startup Task ===&lt;br /&gt;
&lt;br /&gt;
Initialisiere &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; beim Start deiner Anwendung mit der DSN deines Sentry-Projekts:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;&amp;lt;DSN&amp;gt;&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die [[#Demo Library|Demo-Library]] ruft im Startup Task ebenfalls die Initialisierung auf. Quelle: &amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init Sentry on lbs startup&lt;br /&gt;
Do tSentry.$init()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In einer produktiven Anwendung sollte die DSN explizit oder aus einer Konfiguration übergeben werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;https://PUBLIC_KEY@sentry.io/PROJECT_ID&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; Speichere die DSN in einer Datenbank, einer Konfigurationstabelle oder einem Config File. So kann sie pro Kunde, Umgebung oder Installation geändert werden, ohne die Library neu auszuliefern.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Testcall ===&lt;br /&gt;
&lt;br /&gt;
Nach der Initialisierung kann ein erstes Testevent gesendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello World!&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles korrekt eingerichtet ist, erscheint das Event im Sentry-Projekt.&lt;br /&gt;
&lt;br /&gt;
=== Proxy konfigurieren ===&lt;br /&gt;
&lt;br /&gt;
Falls die Anwendung in einem geschützten Netzwerk läuft, kann ein Proxy gesetzt werden. Die Methode befindet sich im Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.iOSentry.$setProxy(&#039;proxy.example.local&#039;,&#039;8080&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die interne Implementierung setzt den Proxy vor dem HTTP-Request:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Configure proxy; needed when sending data out of secured networks&lt;br /&gt;
If not(isclear(iProxyHost))&amp;amp;not(isclear(iProxyPort))&lt;br /&gt;
	HTTPSetProxyServer (iProxyHost,iProxyPort)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sentry aktivieren oder deaktivieren ===&lt;br /&gt;
&lt;br /&gt;
OSentry kann zentral ein- oder ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; Deaktiviere Sentry in der Entwicklungs-Version standardmäßig oder verwende eine separate Entwicklungs-DSN. So landen lokale Tests, Debug-Fehler und absichtlich ausgelöste Exceptions nicht im produktiven Sentry-Projekt.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$setStatus(1)     ## aktiv&lt;br /&gt;
Do tSentry.$setStatus(0)     ## inaktiv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; wird vor dem Senden geprüft:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Check if Sentry is enabled&lt;br /&gt;
If iStatus=0|isclear(iStatus)&lt;br /&gt;
	Quit method 0&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite zeigt die minimale Integration in eine bestehende Omnis-Anwendung.&lt;br /&gt;
&lt;br /&gt;
=== Klassen übernehmen ===&lt;br /&gt;
&lt;br /&gt;
Kopiere &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; in deine Library.&lt;br /&gt;
&lt;br /&gt;
=== Task Variable erstellen ===&lt;br /&gt;
&lt;br /&gt;
In der Startup Task:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Name !! Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sentry initialisieren ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;https://PUBLIC_KEY@sentry.io/PROJECT_ID&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL.$init&amp;lt;/code&amp;gt; delegiert an das Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init of the main sentry object&lt;br /&gt;
Do iOSentry.$init(pDSN)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message senden ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die [[#Demo Library|Demo-Library]] verwendet genau diesen Aufruf im Button &amp;lt;code&amp;gt;Trigger a message&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.message.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exception senden ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== In Sentry prüfen ===&lt;br /&gt;
&lt;br /&gt;
In Sentry sollte anschließend ein neues Event sichtbar sein. Je nach Event-Typ enthält es:&lt;br /&gt;
&lt;br /&gt;
* Message&lt;br /&gt;
* Level&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|User-Kontext]]&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]]&lt;br /&gt;
* Omnis-Kontextinformationen&lt;br /&gt;
&lt;br /&gt;
== Events erfassen ==&lt;br /&gt;
&lt;br /&gt;
OSentryHL ist die empfohlene Einstiegsschicht für Applikationscode. Die Klasse bietet sprechende Methoden für typische Event-Arten und ruft intern &amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
&lt;br /&gt;
=== Message ===&lt;br /&gt;
&lt;br /&gt;
Eine einfache Information wird mit &amp;lt;code&amp;gt;$captureMessage&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello World!&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an Info Message&lt;br /&gt;
Do iOSentry.$captureException(pMessage,3,,&#039;info&#039;,kFalse,,kFalse) Returns code&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Level: &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;&lt;br /&gt;
* Kein [[#Stacktrace und Kontext|Stacktrace]]&lt;br /&gt;
* Kein [[#Tags, Extras und User-Kontext|User Interface]]&lt;br /&gt;
* Geeignet für einfache Statusmeldungen oder technische Hinweise&lt;br /&gt;
&lt;br /&gt;
=== Log ===&lt;br /&gt;
&lt;br /&gt;
Ein Log-Event wird mit &amp;lt;code&amp;gt;$captureLog&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureLog(&#039;Uh oh this is a Log because something went wrong&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a Log Sentry Report&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;Log&#039;,&#039;warning&#039;,1,0,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Level: &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]] aktiv&lt;br /&gt;
* Exception Interface in diesem Wrapper deaktiviert&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|User Interface]] aktiv&lt;br /&gt;
&lt;br /&gt;
=== Generische Exception ===&lt;br /&gt;
&lt;br /&gt;
Eine generische Exception wird mit &amp;lt;code&amp;gt;$captureException&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture a generic Exception&lt;br /&gt;
#Add any custom tags / extras&lt;br /&gt;
Do $cinst.$addTag(&#039;Custom Test Tag&#039;,&#039;Euromnis&#039;)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; || Text, der in Sentry als Message sichtbar ist&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; || Fehlercode oder fachlicher Code&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExcType&amp;lt;/code&amp;gt; || Exception-Typ für Benennung und Gruppierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pLevel&amp;lt;/code&amp;gt; || Sentry-Level&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Gültige Levels:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception ===&lt;br /&gt;
&lt;br /&gt;
SQL-Fehler können mit &amp;lt;code&amp;gt;$captureSQLException&amp;lt;/code&amp;gt; gemeldet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureSQLException(&#039;SQL statement failed&#039;,stat)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Fügt die Datenbank als [[#Tags, Extras und User-Kontext|Tag]] hinzu&lt;br /&gt;
* Fügt SQL-Text als [[#Tags, Extras und User-Kontext|Extra]] hinzu&lt;br /&gt;
* Fügt native Datenbankfehlermeldung als [[#Tags, Extras und User-Kontext|Extra]] hinzu&lt;br /&gt;
* Sendet das Event als &amp;lt;code&amp;gt;SQL-Exception&amp;lt;/code&amp;gt; mit Level &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deprecated Call ===&lt;br /&gt;
&lt;br /&gt;
Veraltete Codepfade können gezielt gemeldet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureDeprecatedCall()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Wrapper eignet sich, um zu erkennen, ob alter Code in produktiven Systemen noch ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
=== Frei konfigurierbares Event ===&lt;br /&gt;
&lt;br /&gt;
Für Sonderfälle gibt es &amp;lt;code&amp;gt;$captureAnything&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureAnything(&#039;Text&#039;,1001,&#039;Custom Type&#039;,&#039;error&#039;,kTrue,kTrue,kTrue)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Capture a generic Sentry Report (max configurability)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Methode bietet maximale Flexibilität. Für wiederkehrende Exception-Typen sollte aber eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; angelegt werden. Siehe [[#Eigene Exceptions standardisieren|04 Eigene Exceptions standardisieren]].&lt;br /&gt;
&lt;br /&gt;
== Eigene Exceptions standardisieren ==&lt;br /&gt;
&lt;br /&gt;
Wenn ein Exception-Typ mehrfach in der Anwendung vorkommt, sollte er nicht überall manuell mit &amp;lt;code&amp;gt;$captureException&amp;lt;/code&amp;gt; aufgebaut werden. Besser ist eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dadurch entsteht eine zentrale, wiederverwendbare Definition für:&lt;br /&gt;
&lt;br /&gt;
* Exception-Typ&lt;br /&gt;
* Sentry-Level&lt;br /&gt;
* Fehlercode&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]]&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]]/[[#Tags, Extras und User-Kontext|User]]/Exception Interface&lt;br /&gt;
&lt;br /&gt;
Die automatisch gesetzten [[#Tags, Extras und User-Kontext|Tags und Extras]] aus &amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; müssen in solchen Wrappern nicht erneut ergänzt werden. Eigene Exception-Methoden setzen nur zusätzliche Werte, die für diesen standardisierten Exception-Typ relevant sind.&lt;br /&gt;
&lt;br /&gt;
=== Warum über OSentryHL? ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ist die Abstraktionsschicht für Applikationscode. Sie kapselt die Details von &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und sorgt dafür, dass Aufrufe in der Anwendung kurz und konsistent bleiben.&lt;br /&gt;
&lt;br /&gt;
Bestehende Beispiele aus &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Empfohlenes Muster ===&lt;br /&gt;
&lt;br /&gt;
Für jeden standardisierten Exception-Typ wird eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; erstellt.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a validation exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Field&#039;,pField)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Invalid Value&#039;,pValue)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,2001,&#039;Validation-Exception&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mögliche Parameter der neuen Methode:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Beispiel !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;Invalid customer number&#039;&amp;lt;/code&amp;gt; || Sentry Message&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pModule&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;Customer&#039;&amp;lt;/code&amp;gt; || Filterbarer Tag&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pField&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;cu_number&#039;&amp;lt;/code&amp;gt; || Diagnoseinformation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pValue&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;ABC&#039;&amp;lt;/code&amp;gt; || Diagnoseinformation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der Applikationscode bleibt dadurch einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureValidationException(&#039;Invalid customer number&#039;,&#039;Customer&#039;,&#039;cu_number&#039;,cu_number)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel: Business Rule Exception ===&lt;br /&gt;
&lt;br /&gt;
Neue Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a business rule violation&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addTag(&#039;Business Rule&#039;,pRuleName)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Details&#039;,pDetails)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aufruf in der Anwendung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureBusinessRuleViolation(&#039;Invoice cannot be posted&#039;,&#039;Invoice&#039;,&#039;PostingAllowed&#039;,&#039;Invoice is missing customer&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel: Integration Exception ===&lt;br /&gt;
&lt;br /&gt;
Neue Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an integration exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Integration&#039;,pSystem)&lt;br /&gt;
Do $cinst.$addTag(&#039;Endpoint&#039;,pEndpoint)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Payload&#039;,pPayload)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Response&#039;,pResponse)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,4001,&#039;Integration-Exception&#039;,&#039;error&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aufruf in der Anwendung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureIntegrationException(&#039;External API request failed&#039;,&#039;ERP&#039;,&#039;/api/customer&#039;,jsonPayload,responseText)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Namenskonventionen ===&lt;br /&gt;
&lt;br /&gt;
Empfehlung für neue Methoden:&lt;br /&gt;
&lt;br /&gt;
* Methodenname beginnt mit &amp;lt;code&amp;gt;$capture&amp;lt;/code&amp;gt;&lt;br /&gt;
* Der fachliche Typ steht im Methodennamen&lt;br /&gt;
* Der Sentry Exception Type ist stabil und ändert sich nicht laufend&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]] sind kurz und filterbar&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]] dürfen länger sein und Diagnoseinformationen enthalten&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureValidationException&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureBusinessRuleViolation&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureIntegrationException&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$capturePermissionViolation&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureConfigurationError&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error Codes ===&lt;br /&gt;
&lt;br /&gt;
Verwende feste Fehlercodes für standardisierte Exception-Typen. Dadurch können Events in Sentry besser gefiltert und wiedererkannt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Code !! Exception Type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Validation-Exception&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Business-Rule-Violation&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Integration-Exception&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;5001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Configuration-Error&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wann nicht standardisieren? ===&lt;br /&gt;
&lt;br /&gt;
Nicht jeder Einzelfall braucht eine eigene Methode. Für einmalige technische Tests oder sehr spezielle Fälle reicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald ein Exception-Typ aber mehrfach vorkommt oder fachlich relevant ist, sollte er als eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
== Tags, Extras und User-Kontext ==&lt;br /&gt;
&lt;br /&gt;
Tags, Extras und User-Kontext reichern Sentry-Events mit zusätzlichen Informationen an. Diese Informationen helfen beim Filtern, Gruppieren und Analysieren.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-tags.png|900px|Sentry Tags und User-Kontext]]&lt;br /&gt;
&lt;br /&gt;
=== Tags ===&lt;br /&gt;
&lt;br /&gt;
Tags sind kurze, filterbare Werte.&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* Datenbank&lt;br /&gt;
* Kunde&lt;br /&gt;
* Modul&lt;br /&gt;
* Umgebung&lt;br /&gt;
* Error Code&lt;br /&gt;
* Omnis-Version&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add a Tag to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addTag(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Adds a tag to the next request processed&lt;br /&gt;
Do iTagList.$add(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$addTag(&#039;Module&#039;,&#039;Invoice&#039;)&lt;br /&gt;
Do tSentry.$addTag(&#039;Customer&#039;,&#039;10001&#039;)&lt;br /&gt;
Do tSentry.$captureException(&#039;Invoice posting failed&#039;,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Extras ===&lt;br /&gt;
&lt;br /&gt;
Extras sind Detailinformationen, die nicht primär zum Filtern gedacht sind.&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* SQL-Text&lt;br /&gt;
* Native Datenbankfehlermeldung&lt;br /&gt;
* Payload&lt;br /&gt;
* Response Body&lt;br /&gt;
* interne IDs&lt;br /&gt;
* zusätzliche Debug-Informationen&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add an Extra to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addExtra(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Adds extra information to the next request being processed&lt;br /&gt;
Do iExtraList.$add(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel aus der SQL Exception:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Automatische Tags ===&lt;br /&gt;
&lt;br /&gt;
Die folgenden Tags werden bei jedem Event automatisch von &amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; ergänzt. Sie müssen bei eigenen Exceptions nicht erneut gesetzt werden. Eigene Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; sollten nur zusätzliche, fachlich oder technisch relevante Tags hinzufügen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; fügt mehrere Tags automatisch hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add static tags&lt;br /&gt;
Do iTagList.$add(&#039;Omnisversion&#039;,sys(1))&lt;br /&gt;
Calculate systemversionRow as systemversion()&lt;br /&gt;
Do iTagList.$add(&#039;Plattform&#039;,con(sys(8),pick(systemversionRow.server,&#039;&#039;,&#039; SRV&#039;)))&lt;br /&gt;
Do iTagList.$add(&#039;OS Version&#039;,con(systemversionRow.major,&#039;.&#039;,systemversionRow.minor,&#039;.&#039;,systemversionRow.build))&lt;br /&gt;
Do iTagList.$add(&#039;error_code&#039;,pErrorCode)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Automatisch gesendete Tags:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tag !! Herkunft !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Omnisversion&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;sys(1)&amp;lt;/code&amp;gt; || Zeigt, mit welcher Omnis-Version das Event erzeugt wurde&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Plattform&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;sys(8)&amp;lt;/code&amp;gt; und Server-Flag aus &amp;lt;code&amp;gt;systemversion()&amp;lt;/code&amp;gt; || Unterscheidet Plattform und Server Runtime&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OS Version&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;systemversionRow.major/minor/build&amp;lt;/code&amp;gt; || Zeigt die Betriebssystemversion&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;error_code&amp;lt;/code&amp;gt; || Parameter &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; || Verbindet das Event mit dem übergebenen Fehlercode&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Beispiel für eine eigene Exception: Der Wrapper muss nicht erneut &amp;lt;code&amp;gt;Omnisversion&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;OS Version&amp;lt;/code&amp;gt; setzen. Er ergänzt nur das, was für diesen Exception-Typ zusätzlich hilfreich ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addTag(&#039;Business Rule&#039;,pRuleName)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Automatische Extras ===&lt;br /&gt;
&lt;br /&gt;
Auch die folgenden Extras werden bei jedem Event automatisch ergänzt. Bei eigenen Exceptions müssen nur zusätzliche Extras gesetzt werden, zum Beispiel ein SQL-Statement, ein Payload oder fachliche Zusatzdaten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; fügt offene Fenster, offene Reports und die aktuelle Printfile hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Static extra 1: All open windows&lt;br /&gt;
Do $root.$iwindows.$makelist($ref.$name) Returns nameList&lt;br /&gt;
For i from 1 to nameList.$linecount step 1&lt;br /&gt;
	Calculate windows as con(windows,&#039;, &#039;,nameList.[i].1)&lt;br /&gt;
End For&lt;br /&gt;
Calculate windows as right(windows,len(windows)-2)&lt;br /&gt;
Do iExtraList.$add(&#039;Open Windows&#039;,windows)&lt;br /&gt;
&lt;br /&gt;
# Static extra 2: All open reports&lt;br /&gt;
Do $root.$ireports.$makelist($ref.$name) Returns nameList&lt;br /&gt;
For i from 1 to nameList.$linecount step 1&lt;br /&gt;
	Calculate reports as con(reports,&#039;, &#039;,nameList.[i].1)&lt;br /&gt;
End For&lt;br /&gt;
Calculate reports as right(reports,len(reports)-2)&lt;br /&gt;
Do iExtraList.$add(&#039;Open Reports&#039;,reports)&lt;br /&gt;
Do iExtraList.$add(&#039;Current Printfile&#039;,$root.$prefs.$printfile)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Automatisch gesendete Extras:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Extra !! Herkunft !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Open Windows&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$iwindows.$makelist($ref.$name)&amp;lt;/code&amp;gt; || Zeigt, welche Fenster im Moment des Events offen waren&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Open Reports&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$ireports.$makelist($ref.$name)&amp;lt;/code&amp;gt; || Zeigt, welche Reports im Moment des Events offen waren&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Current Printfile&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$prefs.$printfile&amp;lt;/code&amp;gt; || Zeigt die aktuell gesetzte Printfile&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Beispiel für zusätzliche Extras in einem eigenen Wrapper:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addExtra(&#039;Payload&#039;,pPayload)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Response&#039;,pResponse)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,4001,&#039;Integration-Exception&#039;,&#039;error&#039;,1,1,1) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== User-Kontext ===&lt;br /&gt;
&lt;br /&gt;
Der User-Kontext ordnet ein Event einem betroffenen Benutzer zu. In Sentry erscheint dadurch ein eigener User-Bereich, und Events können nach Benutzer gefiltert oder gruppiert werden. Das ist besonders hilfreich, wenn ein Fehler nur bei einzelnen Kunden, Arbeitsplätzen oder Benutzerkonten auftritt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; unterstützt drei User-Felder:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feld !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt; || stabile interne Benutzer-ID oder Kundennummer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;username&amp;lt;/code&amp;gt; || lesbarer Benutzername&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;email&amp;lt;/code&amp;gt; || E-Mail-Adresse, falls sie übertragen werden darf&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der User-Kontext wird nur in das Event geschrieben, wenn das User Interface beim Capture-Aufruf aktiviert ist. Die Standardmethode &amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; hat &amp;lt;code&amp;gt;pUserInterface&amp;lt;/code&amp;gt; standardmäßig auf &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt;. Einzelne High-Level-Methoden können das bewusst deaktivieren, zum Beispiel &amp;lt;code&amp;gt;$captureMessage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; kann User-Daten an das Event anhängen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Sets userinformation for the next request being processed&lt;br /&gt;
Calculate iUserID as pID&lt;br /&gt;
Calculate iUserName as pName&lt;br /&gt;
Calculate iUserEmail as pEmail&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das User Interface wird so generiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Create user data row&lt;br /&gt;
Do UserdataRow.$define(id,email,username)&lt;br /&gt;
&lt;br /&gt;
Calculate UserdataRow.id as iUserID&lt;br /&gt;
Calculate UserdataRow.email as iUserEmail&lt;br /&gt;
Calculate UserdataRow.username as iUserName&lt;br /&gt;
&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;user&#039;,&#039;&#039;)&lt;br /&gt;
Do JSON.$setobject(&#039;user&#039;,UserdataRow)&lt;br /&gt;
&lt;br /&gt;
Calculate jsonString as OJSON.$formatjson(JSON.$getjson())&lt;br /&gt;
&lt;br /&gt;
Quit method jsonString&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die aktuelle Demo-Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; verwendet feste Testdaten. Quelle: &amp;lt;code&amp;gt;OSentryHL.$setUser&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Set the User which should be linked to the Sentry Issue&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte diese Methode angepasst und parametrisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(pUserID,pUserName,pUserEmail)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Empfohlen ist, den User nach Login oder beim Wechsel des aktiven Benutzers zentral zu setzen. Bei anonymen oder sensiblen Installationen kann statt Name und E-Mail auch nur eine interne ID oder ein pseudonymisierter Wert verwendet werden.&lt;br /&gt;
&lt;br /&gt;
=== Datenschutz ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #72777d; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Datenschutz:&#039;&#039;&#039; Prüfe vor produktiver Nutzung, welche Daten an Sentry gesendet werden. Besonders kritisch sind personenbezogene Daten, SQL-Statements, Zugangsdaten, Tokens und interne Pfade.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Besonders kritisch sind:&lt;br /&gt;
&lt;br /&gt;
* personenbezogene Daten&lt;br /&gt;
* Kundendaten&lt;br /&gt;
* SQL-Statements mit Werten&lt;br /&gt;
* Zugangsdaten&lt;br /&gt;
* Tokens&lt;br /&gt;
* interne Pfade&lt;br /&gt;
&lt;br /&gt;
Tags und Extras sollten so gestaltet werden, dass sie für die Fehleranalyse hilfreich sind, aber keine unnötigen sensiblen Daten übertragen.&lt;br /&gt;
&lt;br /&gt;
== Stacktrace und Kontext ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; erzeugt einen Omnis-spezifischen Stacktrace und übergibt ihn an Sentry. Dadurch sieht man in Sentry nicht nur eine Fehlermeldung, sondern auch Klassen, Methoden, Zeilen und Variablenkontext. Ergänzende Informationen zu [[#Tags, Extras und User-Kontext|Tags, Extras und User-Kontext]] stehen auf der separaten Kontext-Seite.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-stack.png|900px|Sentry Stacktrace mit Omnis-Kontext]]&lt;br /&gt;
&lt;br /&gt;
=== Stack lesen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateStacktraceInterface&amp;lt;/code&amp;gt; verwendet &amp;lt;code&amp;gt;sys(192)&amp;lt;/code&amp;gt;, um den aktuellen Omnis-Stack zu lesen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Clean up the Stacklist (remove OSentry classes from the stack)&lt;br /&gt;
Do sys(192) Returns sys192List&lt;br /&gt;
For sys192List.$line from 1 to sys192List.$linecount step 1&lt;br /&gt;
	Set reference class to sys192List.classitem&lt;br /&gt;
	If pos(&#039;OSentry&#039;,class.$name)&amp;gt;0|pos(&#039;OSentryHL&#039;,class.$name)&amp;gt;0&lt;br /&gt;
		Do sys192List.[sys192List.$line].$selected.$assign(kTrue)&lt;br /&gt;
	End If&lt;br /&gt;
End For&lt;br /&gt;
Do sys192List.$remove(kListDeleteSelected)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Interne Frames von &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; werden entfernt, damit in Sentry die fachlich relevanten Stellen sichtbar bleiben.&lt;br /&gt;
&lt;br /&gt;
=== SQL-Error Frames entfernen ===&lt;br /&gt;
&lt;br /&gt;
Bestimmte interne SQL-Fehlerframes werden ebenfalls entfernt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Remove some other classes which we do not want to display&lt;br /&gt;
If sys192List.1.method=&#039;$sqlerror&#039;&lt;br /&gt;
	Do sys192List.$remove(1)&lt;br /&gt;
Else If sys192List.1.method=&#039;$statementerror&#039;&lt;br /&gt;
	Do sys192List.$remove(1)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frames erzeugen ===&lt;br /&gt;
&lt;br /&gt;
Für jeden Stack-Eintrag werden Funktion, Zeilennummer und Kontextzeile erzeugt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Loop through every item on the omnis stack&lt;br /&gt;
For sys192List.$line from 1 to sys192List.$linecount step 1&lt;br /&gt;
	Set reference class to sys192List.classitem&lt;br /&gt;
	Calculate className as class.$name&lt;br /&gt;
	&lt;br /&gt;
	# Create the content row&lt;br /&gt;
	Do contentRow.$define(vars,function,pre_context,context_line,lineno,filename,post_context)&lt;br /&gt;
	Calculate contentRow.lineno as sys192List.line&lt;br /&gt;
	Calculate contentRow.filename as testFileName&lt;br /&gt;
	Calculate contentRow.context_line as sys192List.linetext&lt;br /&gt;
	If isclear(sys192List.object)&lt;br /&gt;
		Calculate contentRow.function as con(className,&#039;.&#039;,sys192List.method) ## If it&#039;s a class method&lt;br /&gt;
	Else&lt;br /&gt;
		Calculate contentRow.function as con(className,&#039;.&#039;,sys192List.object,&#039;.&#039;,sys192List.method) ## If it&#039;s a method of an object of a class (e.g. Headedlist)&lt;br /&gt;
	End If&lt;br /&gt;
	Do contentList.$add(contentRow)&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablen aufnehmen ===&lt;br /&gt;
&lt;br /&gt;
Pro Stackframe werden Instance Variablen und Parameter gesammelt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Get all iVars&lt;br /&gt;
Do varList.$define(name,value)&lt;br /&gt;
Set reference class to sys192List.inst&lt;br /&gt;
Do $cinst.$getVars(&#039;ivars&#039;,class) Returns varList&lt;br /&gt;
&lt;br /&gt;
# Get all params&lt;br /&gt;
Calculate paramList as sys192List.params&lt;br /&gt;
For paramList.$line from 1 to paramList.$linecount step 1&lt;br /&gt;
	If not(paramList.value=&#039;(Not empty)&#039;)&lt;br /&gt;
		Do varList.$add(paramList.name,paramList.value)&lt;br /&gt;
	Else&lt;br /&gt;
		Do varList.$add(paramList.name,&#039;(Not empty)&#039;)&lt;br /&gt;
	End If&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pre- und Post-Context ===&lt;br /&gt;
&lt;br /&gt;
OSentry fügt Methodenzeilen vor und nach der aktuellen Zeile hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Pre Context (all method lines before the error occured)&lt;br /&gt;
Set reference method to sys192List.methoditem&lt;br /&gt;
Do precontextList.$define(line)&lt;br /&gt;
For i from 1 to sys192List.line-1 step 1&lt;br /&gt;
	Do precontextList.$add(method.$methodlines.[i].$text)&lt;br /&gt;
End For&lt;br /&gt;
&lt;br /&gt;
# Post Context (all method lines after the error occured&lt;br /&gt;
Do postcontextList.$define(line)&lt;br /&gt;
For i from sys192List.line+1 to method.$methodlines.$count step 1&lt;br /&gt;
	Do postcontextList.$add(method.$methodlines.[i].$text)&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablentypen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$getVars&amp;lt;/code&amp;gt; unterstützt Basisvariablen, Rows und Lists.&lt;br /&gt;
&lt;br /&gt;
Basisvariablen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
If varType=&#039;char&#039;|varType=&#039;boolean&#039;|varType=&#039;integer&#039;|varType=&#039;number&#039;|varType=&#039;date&#039;&lt;br /&gt;
	Calculate varContent as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	Do varList.$add(varName,varContent)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Else If varType=&#039;row&#039;&lt;br /&gt;
	Calculate varRow as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	If varRow.$colcount=0&lt;br /&gt;
		Do varList.$add(varName,&#039;(Empty)&#039;)&lt;br /&gt;
	Else&lt;br /&gt;
		For Z2 from 1 to varRow.$colcount step 1&lt;br /&gt;
			Calculate varContent as con(varContent,varRow.$cols.[Z2].$name,&#039;: &#039;,varRow.[Z2],&#039;, &#039;)&lt;br /&gt;
		End For&lt;br /&gt;
		Do varList.$add(varName,varContent)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lists:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Else If varType=&#039;list&#039;&lt;br /&gt;
	Calculate varListType as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	Calculate varContent as con(&#039;Colcount: &#039;,varListType.$colcount,&#039;, &#039;,&#039;Linecount: &#039;,varListType.$linecount,&#039;, &#039;,&#039;Current Line: &#039;,varListType.$line)&lt;br /&gt;
	If varListType.$linecount=0&amp;amp;varListType.$line=0&amp;amp;varListType.$colcount=0&lt;br /&gt;
		Do varList.$add(varName,&#039;(Empty)&#039;)&lt;br /&gt;
		Calculate varContent as &#039;&#039;&lt;br /&gt;
	Else&lt;br /&gt;
		For Z3 from 1 to varListType.$colcount step 1&lt;br /&gt;
			Calculate colName as varListType.$cols.[Z3].$name&lt;br /&gt;
			Calculate varContent as con(varContent,&#039;  &#039;,colName,&#039;: &#039;,varListType.[colName])&lt;br /&gt;
		End For&lt;br /&gt;
		Do varList.$add(varName,varContent)&lt;br /&gt;
		Calculate varContent as &#039;&#039;&lt;br /&gt;
	End If&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
&lt;br /&gt;
Stacktrace und Variablenkontext sind sehr hilfreich, können aber sensible Daten enthalten. Vor produktiver Nutzung sollte geprüft werden, ob bestimmte Variablen anonymisiert oder ausgeschlossen werden müssen.&lt;br /&gt;
&lt;br /&gt;
== Interne Architektur ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite beschreibt die produktiv relevanten Klassen &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Klassenübersicht ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Rolle&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; || High-Level-Adapter für Applikationscode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; || Low-Level-Adapter für JSON, [[#Stacktrace und Kontext|Stacktrace]] und HTTP&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Startup und Beispiel für Initialisierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Code für [[#Stacktrace und Kontext|Stacktrace]]-Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-DB Initialisierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt; || SQLite Session für [[#Demo Library|Demo]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Empfohlener Aufrufweg ===&lt;br /&gt;
&lt;br /&gt;
Applikationscode sollte &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; verwenden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; delegiert anschließend an &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ablauf eines Events ===&lt;br /&gt;
&lt;br /&gt;
# Applikationscode ruft Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; fügt bei Bedarf [[#Tags, Extras und User-Kontext|Tags und Extras]] hinzu.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ruft &amp;lt;code&amp;gt;iOSentry.$captureException(...)&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; prüft, ob Sentry aktiv ist.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; erzeugt JSON.&lt;br /&gt;
# [[#Stacktrace und Kontext|Stacktrace]], Exception Interface und [[#Tags, Extras und User-Kontext|User Interface]] werden optional ergänzt.&lt;br /&gt;
# HTTP Header und Sentry Auth Header werden erstellt.&lt;br /&gt;
# JSON wird per HTTPS an Sentry gesendet.&lt;br /&gt;
# Bei Erfolg werden [[#Tags, Extras und User-Kontext|Tags und Extras]] geleert.&lt;br /&gt;
# Bei Fehler wird der JSON Report lokal gespeichert.&lt;br /&gt;
&lt;br /&gt;
=== DSN Parsing ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$init&amp;lt;/code&amp;gt; zerlegt die DSN:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Parse the DSN into Public Key, Host and Project ID&lt;br /&gt;
If len(pDSN)&amp;gt;5&lt;br /&gt;
	Calculate iDSN as pDSN&lt;br /&gt;
	Calculate part1 as strtok(&#039;iDSN&#039;,&#039;@&#039;)&lt;br /&gt;
	Calculate iProtocol as strtok(&#039;part1&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iProtocol as left(iProtocol,len(iProtocol)-1)&lt;br /&gt;
	Do strtok(&#039;part1&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iPubKey as strtok(&#039;part1&#039;,&#039;:&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Calculate iHost as strtok(&#039;iDSN&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iProID as iDSN&lt;br /&gt;
	&lt;br /&gt;
	#Save the values for the next startup&lt;br /&gt;
	Calculate $cclass.$ivardefs.iPubKey.$objinitval as con(&#039;&amp;quot;&#039;,iPubKey,&#039;&amp;quot;&#039;)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iHost.$objinitval as con(&#039;&amp;quot;&#039;,iHost,&#039;&amp;quot;&#039;)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iProID.$objinitval as con(&#039;&amp;quot;&#039;,iProID,&#039;&amp;quot;&#039;)&lt;br /&gt;
End If&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== JSON-Erzeugung ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; ist die zentrale Methode für den Payload. Sie setzt unter anderem:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;event_id&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;logger&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;platform&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;culprit&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;timestamp&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sdk&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;message&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;level&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;tags&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;extra&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;exception&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;stacktrace&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auszug:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add all required fields (those are required from the API)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;event_id&#039;,$cinst.$generateUUID()) ## auto generated UUID 4&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;logger&#039;,logger)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;platform&#039;,platform)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;culprit&#039;,culprit)&lt;br /&gt;
#Do JSON.$addmember(&#039;&#039;,&#039;release&#039;,release)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;timestamp&#039;,timestamp)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;sdk&#039;,&#039;&#039;)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;message&#039;,pErrorText)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;level&#039;,pLevel)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;tags&#039;,&#039;&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== HTTP-Kommunikation ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; sendet den erzeugten JSON-Payload an Sentry:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Generate HTTP Auth header&lt;br /&gt;
Begin text block&lt;br /&gt;
Text:Sentry sentry_version=7,&lt;br /&gt;
Text:sentry_timestamp=[$cinst.$getUnixTimestamp()],&lt;br /&gt;
Text:sentry_key=[iPubKey],&lt;br /&gt;
Text:sentry_client=omnis/1.0&lt;br /&gt;
End text block&lt;br /&gt;
Get text block auth&lt;br /&gt;
&lt;br /&gt;
#Generate header list&lt;br /&gt;
Calculate Host as &#039;sentry.io&#039;&lt;br /&gt;
Calculate Url as con(&#039;/api/&#039;,iProID,&#039;/store/&#039;)&lt;br /&gt;
Do HdrList.$define(wert,name)&lt;br /&gt;
Do HdrList.$add(&#039;User-Agent&#039;,&#039;omnis/1.0&#039;)&lt;br /&gt;
Do HdrList.$add(&#039;Content-Type&#039;,&#039;application/json&#039;)&lt;br /&gt;
Do HdrList.$add(&#039;Content-Length&#039;,binlength(json))&lt;br /&gt;
Do HdrList.$add(&#039;X-Sentry-Auth&#039;,auth)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anschließend wird der Request über &amp;lt;code&amp;gt;HTTPPost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HTTPSend&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;HTTPRead&amp;lt;/code&amp;gt; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
=== Fehlerbehandlung beim Senden ===&lt;br /&gt;
&lt;br /&gt;
Wenn der Socket nicht geöffnet werden kann:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPPost (Host,Url,,HdrList,443,kTrue,kTrue) Returns Socket&lt;br /&gt;
If Socket&amp;lt;0&lt;br /&gt;
	#Error when opening connection -&amp;gt; save json as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,con(&#039;Error &#039;,Socket,&#039; when performing HTTPPost&#039;))&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -1&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn das Senden fehlschlägt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPSend (Socket,json) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0&lt;br /&gt;
	# Error while sending data -&amp;gt; save json as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,con(&#039;Erorr &#039;,byteCount,&#039; when performing HTTPSend&#039;))&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -2&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn die Antwort nicht erfolgreich ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPRead (Socket,Buffer) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0|not(pos(&#039;200 OK&#039;,Buffer))&lt;br /&gt;
	# JSON may be corrupted or contains errors -&amp;gt; save json and the buffer as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,Buffer)&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -3&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Lokales Speichern ===&lt;br /&gt;
&lt;br /&gt;
Bei Fehlern wird der JSON Report lokal im Omnis-Installationsordner gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Writes the json and the http buffer to a file in the omnis installation folder&lt;br /&gt;
Calculate path as sys(115)&lt;br /&gt;
Calculate filename as con(&#039;Sentryreport_&#039;,$cinst.$getUnixTimestamp(),&#039;.json&#039;)&lt;br /&gt;
Do fOP.$createfile(con(path,filename)) Returns err&lt;br /&gt;
Do fOP.$writecharacter(kUniTypeUTF8,pJSON) Returns err&lt;br /&gt;
If not(isclear(pBuffer))&lt;br /&gt;
	Do fOP.$writecharacter(kUniTypeUTF8,con(kCr,pBuffer),kTrue) Returns err&lt;br /&gt;
End If&lt;br /&gt;
Do fOP.$closefile()&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cleanup ===&lt;br /&gt;
&lt;br /&gt;
Nach erfolgreichem Senden werden [[#Tags, Extras und User-Kontext|Tags und Extras]] gelöscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Clears all extras and tags =&amp;gt; to be used after a sentry request has successfully been sent&lt;br /&gt;
Do iTagList.$clear()&lt;br /&gt;
Do iExtraList.$clear()&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Demo Library ==&lt;br /&gt;
&lt;br /&gt;
Die Demo-Library zeigt, wie &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; initialisiert wird und wie verschiedene [[#Events erfassen|Event-Typen]] aus einer Omnis-Oberfläche heraus an Sentry gesendet werden.&lt;br /&gt;
&lt;br /&gt;
=== Bestandteile ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; || Initialisiert Sentry, SQLite und öffnet das Demo-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; || Demo-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt; || Erzeugt Demo-Stack für Exception&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; || Erstellt SQLite-Demo-Datenbank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt; || SQLite Session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; || Low-Level-Sentry-Adapter&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; || High-Level-Sentry-Adapter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt; initialisiert Sentry, baut eine SQLite Session auf und öffnet das Demo-Fenster. Quelle: &amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init Sentry on lbs startup&lt;br /&gt;
Do tSentry.$init()&lt;br /&gt;
&lt;br /&gt;
#SQLite Session init&lt;br /&gt;
Do $objects.OSLSession.$newref() Returns tOSLSession&lt;br /&gt;
#Calculate tOSLSession.$opencreate as kTrue&lt;br /&gt;
Calculate workingDir as tODatabaseHandler.$getWorkingDir()&lt;br /&gt;
Do con(workingDir,&#039;Sentry_Test.db&#039;) Returns dbLocation&lt;br /&gt;
Do tOSLSession.$logon(dbLocation,&#039;&#039;,&#039;&#039;,&#039;slsession&#039;) Returns #F&lt;br /&gt;
&lt;br /&gt;
#Open Test Window&lt;br /&gt;
Do $windows.FSY_Demo.$openonce(&#039;*&#039;)&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Demo-Fenster ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; enthält folgende Bereiche:&lt;br /&gt;
&lt;br /&gt;
* DSN Configuration&lt;br /&gt;
* DB Status&lt;br /&gt;
* Actions&lt;br /&gt;
&lt;br /&gt;
Wichtige Felder:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feld !! Datenanbindung&lt;br /&gt;
|-&lt;br /&gt;
| DSN || &amp;lt;code&amp;gt;iDSN&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Host || &amp;lt;code&amp;gt;tSentry.iOSentry.iHost&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Public Key || &amp;lt;code&amp;gt;tSentry.iOSentry.iPubKey&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Project ID || &amp;lt;code&amp;gt;tSentry.iOSentry.iProID&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| DB Status || &amp;lt;code&amp;gt;iCurrentDBStatus&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Datei:Demo-window.png|850px|Demo-Fenster der OSentry Library]]&lt;br /&gt;
&lt;br /&gt;
=== DSN setzen ===&lt;br /&gt;
&lt;br /&gt;
Die DSN wird im Feld &amp;lt;code&amp;gt;iDSN&amp;lt;/code&amp;gt; erfasst. Der Button &amp;lt;code&amp;gt;Set DSN&amp;lt;/code&amp;gt; ruft anschließend &amp;lt;code&amp;gt;tSentry.$init(iDSN)&amp;lt;/code&amp;gt; auf. Nach dem Setzen werden Public Key, Host und Project ID aus der DSN gelesen und in den darunterliegenden Feldern angezeigt.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Demo-dsn.svg|850px|DSN-Konfiguration im Demo-Fenster]]&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Set DSN&amp;lt;/code&amp;gt; initialisiert Sentry mit der eingegebenen DSN. Quelle: &amp;lt;code&amp;gt;FSY_Demo.setDSN.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$init(iDSN)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iDSN.$objinitval as con(kSq,iDSN,kSq)&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$showmessage(&#039;DSN set and Sentry initialized!&#039;,&#039;Info&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$redraw()&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== DB Status anzeigen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FSY_Demo.$displayDBState&amp;lt;/code&amp;gt; zeigt, ob die SQLite Session verbunden ist. Quelle: &amp;lt;code&amp;gt;FSY_Demo.$displayDBState&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tOSLSession.$state Returns dbState&lt;br /&gt;
If dbState=&#039;kSessionStateLoggedOff&#039;&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Logged Off&#039;&lt;br /&gt;
Else If dbState=&#039;kSessionStateLoggedOn&#039;&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Logged On&#039;&lt;br /&gt;
Else&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Unkown DB State&#039;&lt;br /&gt;
End If&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$redraw()&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Demo-Datenbank erstellen ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Create Database&amp;lt;/code&amp;gt; ruft &amp;lt;code&amp;gt;ODatabaseHandler.$DBFirstInit&amp;lt;/code&amp;gt; auf. Quelle: &amp;lt;code&amp;gt;FSY_Demo.createDB.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Setup the DB&lt;br /&gt;
	Do tODatabaseHandler.$DBFirstInit() Returns err&lt;br /&gt;
	If err=0&lt;br /&gt;
		Do $cinst.$showmessage(&#039;DB successfully created!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Else&lt;br /&gt;
		Do $cinst.$showmessage(&#039;Error while creating the DB. Make sure that the DB does not already exist.&#039;,&#039;Info&#039;)&lt;br /&gt;
	End If&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$displayDBState()&lt;br /&gt;
	&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Datenbank wird im Arbeitsverzeichnis der Library angelegt. Quelle: &amp;lt;code&amp;gt;ODatabaseHandler.$getWorkingDir&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Quit method con(FileOps.$parentdir($clib.$pathname),pathsep())&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Demo-DB enthält unter anderem:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;dperson&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;drelease&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;dvcs&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a message&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.message.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Log auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a log&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.log.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureLog(&#039;Uh oh this is a Log because something went wrong&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exception auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger an exception&amp;lt;/code&amp;gt; bereitet eine Row und eine List vor und ruft anschließend &amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt; auf. Quelle: &amp;lt;code&amp;gt;FSY_Demo.exception.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do iDummyRow.$define(id,name)&lt;br /&gt;
	Calculate iDummyRow.id as 22&lt;br /&gt;
	Calculate iDummyRow.name as &#039;Tom&#039;&lt;br /&gt;
	&lt;br /&gt;
	Do iDummyList.$define(id,weekday)&lt;br /&gt;
	Do iDummyList.$add(1,&#039;Monday&#039;)&lt;br /&gt;
	Do iDummyList.$add(2,&#039;Tuesday&#039;)&lt;br /&gt;
	Do iDummyList.$add(3,&#039;Wednesday&#039;)&lt;br /&gt;
	Do iDummyList.$add(4,&#039;Thursday&#039;)&lt;br /&gt;
	Do iDummyList.$add(5,&#039;Friday&#039;)&lt;br /&gt;
	Do iDummyList.$add(6,&#039;Saturday&#039;)&lt;br /&gt;
	Do iDummyList.$add(7,&#039;Sunday&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Calculate iDummyList.$line as 5&lt;br /&gt;
	&lt;br /&gt;
	Do iODummy.$dummyMethod(&#039;Important Value&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt; sendet die Exception. Quelle: &amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#In here is some logic&lt;br /&gt;
#This logic would produce an error&lt;br /&gt;
#We send all this information to Sentry&lt;br /&gt;
&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&lt;br /&gt;
Quit method 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deprecated Call auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a deprecated call&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.deprecatedCall.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureDeprecatedCall()&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception Button ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Trigger an SQLException&amp;lt;/code&amp;gt; ist im Export vorhanden, enthält aber noch keinen fertigen Demo-Code. Quelle: &amp;lt;code&amp;gt;FSY_Demo.sqlException.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Code need&#039;s to be written&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Dokumentation der SQL-Erfassung siehe [[#Events erfassen|03 Events erfassen]].&lt;br /&gt;
&lt;br /&gt;
== API Reference ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite dokumentiert die produktiv relevanten Methoden von &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== OSentryHL ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ist die empfohlene Klasse für Applikationscode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$init(pDSN)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Initialisiert das interne &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;-Objekt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init of the main sentry object&lt;br /&gt;
Do iOSentry.$init(pDSN)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureMessage(pMessage)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet eine einfache Info-Message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an Info Message&lt;br /&gt;
Do iOSentry.$captureException(pMessage,3,,&#039;info&#039;,kFalse,,kFalse) Returns code&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureException(pErrorText,pErrorCode,pExcType,pLevel)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet eine generische Exception.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture a generic Exception&lt;br /&gt;
#Add any custom tags / extras&lt;br /&gt;
Do $cinst.$addTag(&#039;Custom Test Tag&#039;,&#039;Euromnis&#039;)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureAnything(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet ein frei konfigurierbares Event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Capture a generic Sentry Report (max configurability)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hinweis: Der Parameter ist im Export als &amp;lt;code&amp;gt;pStacktraveInterface&amp;lt;/code&amp;gt; geschrieben.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureLog(pErrorText)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet ein Log-Event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a Log Sentry Report&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;Log&#039;,&#039;warning&#039;,1,0,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureDeprecatedCall()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Meldet die Ausführung eines veralteten Codepfads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureSQLException(pErrorText,pStat)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Meldet einen SQL-Fehler mit SQL-Text und nativer Datenbankfehlermeldung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addTag(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt einen Tag für das nächste Event hinzu.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add a Tag to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addTag(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addExtra(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt ein Extra für das nächste Event hinzu.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add an Extra to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addExtra(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setStatus(pStatus)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Aktiviert oder deaktiviert Sentry.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Toggels Sentry on or off&lt;br /&gt;
Do iOSentry.$setStatus(pStatus)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setUser()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt im Export feste [[#Demo Library|Demo]]-Userdaten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Set the User which should be linked to the Sentry Issue&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte diese Methode parametrisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== OSentry ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; ist die Low-Level-Klasse für Payload-Erzeugung und Versand.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$init(pDSN)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parst die DSN in Protokoll, Public Key, Host und Project ID.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraceInterface,pUserInterface,pExceptionInterface)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt JSON, sendet es an Sentry und behandelt Fehlerfälle.&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Default !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; ||  || Message&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; ||  || Fehlercode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExcType&amp;lt;/code&amp;gt; ||  || Exception-Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pLevel&amp;lt;/code&amp;gt; ||  || &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pStacktraceInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || [[#Stacktrace und Kontext|Stacktrace]] senden&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pUserInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || [[#Tags, Extras und User-Kontext|User-Kontext]] senden&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExceptionInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || Exception Interface senden&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateJson(...)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den Sentry JSON Payload als Binary.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateStacktraceInterface(pCulprit)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den Omnis-[[#Stacktrace und Kontext|Stacktrace]] inklusive Variablen und Kontextzeilen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateExceptionInterface(pType,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt das Sentry Exception Interface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Generate Row to store in the JSON&lt;br /&gt;
Do exceptionRow.$define(type,value,stacktrace)&lt;br /&gt;
Calculate exceptionRow.type as pType&lt;br /&gt;
Calculate exceptionRow.value as pValue&lt;br /&gt;
Calculate exceptionRow.stacktrace as &#039;sentry.interfaces.stacktrace&#039; ## Tells the exception interface that a stacktrace is passed aswell&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateUserInterface()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den [[#Tags, Extras und User-Kontext|User-Kontext]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addTag(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt einen Tag zur internen Tag-Liste hinzu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addExtra(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt ein Extra zur internen Extra-Liste hinzu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$clearList()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Leert [[#Tags, Extras und User-Kontext|Tags und Extras]] nach einem Request.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setUserData(pID,pName,pEmail)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt Userdaten für den nächsten Request.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setProxy(pProxyHost,pProxyPort)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt Proxy-Informationen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setStatus(pStatus)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt den Sentry-Status.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Toggels Sentry Reports on or off&lt;br /&gt;
Calculate iStatus as pStatus&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$writeJSON(pJSON,pBuffer)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Schreibt fehlgeschlagene Reports lokal in eine Datei.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$getUnixTimestamp()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Gibt den aktuellen UNIX Timestamp zurück.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateUUID()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt eine UUID für die Sentry Event ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Genereates a UUID for the issue id&lt;br /&gt;
Quit method OW3.$makeuuid(kFalse)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Es erscheinen keine Events in Sentry ===&lt;br /&gt;
&lt;br /&gt;
Prüfe zuerst, ob Sentry aktiv ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$setStatus(1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; beendet sich sofort, wenn der Status &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; oder leer ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Check if Sentry is enabled&lt;br /&gt;
If iStatus=0|isclear(iStatus)&lt;br /&gt;
	Quit method 0&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Die DSN ist falsch ===&lt;br /&gt;
&lt;br /&gt;
Prüfe, ob die DSN korrekt aus Sentry kopiert wurde. &amp;lt;code&amp;gt;OSentry.$init&amp;lt;/code&amp;gt; erwartet eine DSN, aus der Public Key, Host und Project ID gelesen werden können.&lt;br /&gt;
&lt;br /&gt;
Nach dem Setzen der DSN sollten in der [[#Demo Library|Demo-Library]] folgende Felder gefüllt sein:&lt;br /&gt;
&lt;br /&gt;
* Host&lt;br /&gt;
* Public Key&lt;br /&gt;
* Project ID&lt;br /&gt;
&lt;br /&gt;
=== Netzwerk oder Proxy blockiert den Request ===&lt;br /&gt;
&lt;br /&gt;
Wenn die Anwendung keinen direkten Zugriff auf Sentry hat, setze einen Proxy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.iOSentry.$setProxy(&#039;proxy.example.local&#039;,&#039;8080&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Intern wird der Proxy vor dem HTTP Request gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
If not(isclear(iProxyHost))&amp;amp;not(isclear(iProxyPort))&lt;br /&gt;
	HTTPSetProxyServer (iProxyHost,iProxyPort)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Report wird lokal gespeichert ===&lt;br /&gt;
&lt;br /&gt;
Wenn &amp;lt;code&amp;gt;HTTPPost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HTTPSend&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;HTTPRead&amp;lt;/code&amp;gt; fehlschlägt, speichert OSentry den Report lokal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Calculate path as sys(115)&lt;br /&gt;
Calculate filename as con(&#039;Sentryreport_&#039;,$cinst.$getUnixTimestamp(),&#039;.json&#039;)&lt;br /&gt;
Do fOP.$createfile(con(path,filename)) Returns err&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Suche im Omnis-Installationsordner nach Dateien mit dem Namen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Sentryreport_&amp;lt;timestamp&amp;gt;.json&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sentry antwortet nicht mit 200 OK ===&lt;br /&gt;
&lt;br /&gt;
Wenn die HTTP-Antwort kein &amp;lt;code&amp;gt;200 OK&amp;lt;/code&amp;gt; enthält, wird der JSON Report ebenfalls lokal gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPRead (Socket,Buffer) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0|not(pos(&#039;200 OK&#039;,Buffer))&lt;br /&gt;
	# JSON may be corrupted or contains errors -&amp;gt; save json and the buffer as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,Buffer)&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -3&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mögliche Ursachen:&lt;br /&gt;
&lt;br /&gt;
* falsche Project ID&lt;br /&gt;
* falscher Public Key&lt;br /&gt;
* ungültige DSN&lt;br /&gt;
* JSON Payload wird von Sentry abgelehnt&lt;br /&gt;
* Netzwerk-Gateway verändert den Request&lt;br /&gt;
&lt;br /&gt;
=== Tags oder Extras erscheinen beim falschen Event ===&lt;br /&gt;
&lt;br /&gt;
[[#Tags, Extras und User-Kontext|Tags und Extras]] werden für den nächsten Request gesammelt. Nach erfolgreichem Request werden sie gelöscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iTagList.$clear()&lt;br /&gt;
Do iExtraList.$clear()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn ein Request fehlschlägt, wird ebenfalls aufgeräumt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$clearList()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prüfe trotzdem, ob in eigenen Wrapper-Methoden Tags und Extras direkt vor dem passenden Capture-Aufruf gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== User-Kontext zeigt Demo-Daten ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL.$setUser&amp;lt;/code&amp;gt; verwendet im Export feste Testdaten:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte die Methode parametrisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(pUserID,pUserName,pUserEmail)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception Demo-Button funktioniert nicht ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Trigger an SQLException&amp;lt;/code&amp;gt; ist im Export noch nicht implementiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Code need&#039;s to be written&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die produktive Methode für SQL-Fehler ist aber vorhanden. Siehe auch [[#Events erfassen|Events erfassen]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureSQLException(&#039;SQL statement failed&#039;,stat)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Zu viele Events ===&lt;br /&gt;
&lt;br /&gt;
Sentry kann sehr schnell viele Events sammeln. Verwende für produktive Systeme:&lt;br /&gt;
&lt;br /&gt;
* klare Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
* sinnvolle Levels&lt;br /&gt;
* gezielte [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* keine Events in sehr häufigen Schleifen&lt;br /&gt;
* keine rein informativen Debug-Events ohne Nutzen&lt;br /&gt;
&lt;br /&gt;
=== Sensible Daten ===&lt;br /&gt;
&lt;br /&gt;
[[#Stacktrace und Kontext|Stacktrace]], Parameter, Instance Variablen, SQL-Text und [[#Tags, Extras und User-Kontext|Extras]] können sensible Daten enthalten. Prüfe vor produktiver Nutzung:&lt;br /&gt;
&lt;br /&gt;
* Welche Variablen werden übertragen?&lt;br /&gt;
* Enthalten SQL-Statements personenbezogene Daten?&lt;br /&gt;
* Werden Tokens oder Passwörter in Extras geschrieben?&lt;br /&gt;
* Sollen bestimmte Werte maskiert werden?&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Sentry&amp;diff=9529</id>
		<title>Sentry</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Sentry&amp;diff=9529"/>
		<updated>2026-06-12T14:06:27Z</updated>

		<summary type="html">&lt;p&gt;Silvan: /* Screenshots */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- MediaWiki source for page: Sentry --&amp;gt;&lt;br /&gt;
&amp;lt;!-- Upload required files before publishing: Sentry-issue.png, Sentry-stack.png, Sentry-tags.png, Sentry-projects.png, Demo-window.svg, Demo-dsn.svg --&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Überblick ==&lt;br /&gt;
&lt;br /&gt;
OSentry ist ein REST-API-Konnektor von Omnis Studio zu Sentry. Der Konnektor sendet Fehler, Messages, Logs und Laufzeitkontext aus Omnis-Anwendungen an Sentry, damit Probleme in produktiven Systemen sichtbar, gruppierbar und analysierbar werden.&lt;br /&gt;
&lt;br /&gt;
Diese Dokumentation beschreibt die [[#Installation|Installation]], die Nutzung in bestehenden Omnis-Anwendungen, die Definition eigener standardisierter Exception-Typen, die interne Struktur und die [[#Demo Library|Demo-Library]].&lt;br /&gt;
&lt;br /&gt;
=== Kernidee ===&lt;br /&gt;
&lt;br /&gt;
OSentry besteht aus zwei produktiv relevanten Klassen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;: High-Level-Adapter für die Anwendung. Diese Klasse sollte von normalem Applikationscode aufgerufen werden.&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;: Low-Level-Adapter für DSN-Parsing, JSON-Erzeugung, [[#Stacktrace und Kontext|Stacktrace]]-Aufbereitung und HTTP-Kommunikation mit Sentry.&lt;br /&gt;
&lt;br /&gt;
Die Anwendung arbeitet im Normalfall mit &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;. Dadurch bleiben Sentry-spezifische Details zentral gekapselt und neue standardisierte Exception-Typen können als eigene Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Hauptfeatures ===&lt;br /&gt;
&lt;br /&gt;
* Direkte Anbindung von Omnis Studio an Sentry über REST API und DSN&lt;br /&gt;
* Erfassen von Exceptions, Messages, Logs und SQL-Fehlern&lt;br /&gt;
* Unterstützung der Sentry-Level &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
* Automatische Omnis-Kontextinformationen&lt;br /&gt;
* Omnis-[[#Stacktrace und Kontext|Stacktrace]] mit Klassen, Methoden, Zeilen und Variablen&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]] für Filterung und Gruppierung&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]] für zusätzliche Diagnoseinformationen&lt;br /&gt;
* Optionaler [[#Tags, Extras und User-Kontext|User-Kontext]]&lt;br /&gt;
* Proxy-Unterstützung&lt;br /&gt;
* Aktivieren und Deaktivieren der Sentry-Übertragung&lt;br /&gt;
* Lokales Speichern von Reports bei Übertragungsfehlern&lt;br /&gt;
&lt;br /&gt;
=== Weiterführende Links ===&lt;br /&gt;
&lt;br /&gt;
* [https://sentry.io/welcome/ Sentry Website]&lt;br /&gt;
* [https://sentry.io/signup/ Sentry Account erstellen]&lt;br /&gt;
* [https://develop.sentry.dev/self-hosted/ Sentry self-hosted]&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite beschreibt, wie OSentry in eine bestehende Omnis-Anwendung integriert wird.&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* Omnis Studio Anwendung&lt;br /&gt;
* Sentry Account oder self-hosted Sentry Installation&lt;br /&gt;
* Ein Sentry-Projekt mit SDK-Typ &amp;lt;code&amp;gt;Other&amp;lt;/code&amp;gt;&lt;br /&gt;
* Die DSN des Sentry-Projekts&lt;br /&gt;
* Netzwerkzugriff auf Sentry&lt;br /&gt;
&lt;br /&gt;
Die exportierte [[#Demo Library|Demo-Library]] wurde mit Omnis &amp;lt;code&amp;gt;11.1&amp;lt;/code&amp;gt; erstellt.&lt;br /&gt;
&lt;br /&gt;
=== Sentry-Projekt erstellen ===&lt;br /&gt;
&lt;br /&gt;
# In Sentry ein neues Projekt erstellen.&lt;br /&gt;
# Als SDK &amp;lt;code&amp;gt;Other&amp;lt;/code&amp;gt; auswählen.&lt;br /&gt;
# Die DSN des Projekts kopieren.&lt;br /&gt;
&lt;br /&gt;
Die DSN wird beim Initialisieren verwendet. &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; zerlegt sie intern in Public Key, Host und Project ID.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-projects.png|900px|Sentry Projektübersicht]]&lt;br /&gt;
&lt;br /&gt;
=== Klassen kopieren ===&lt;br /&gt;
&lt;br /&gt;
Kopiere die folgenden Klassen in deine bestehende Omnis-Library:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Demo-spezifischen Klassen sind für die produktive Integration nicht erforderlich. Damit sind die übrigen Klassen der Demo-Library gemeint, zum Beispiel &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt;. Diese Klassen dienen nur dazu, die [[#Demo Library|Demo-Library]] mit Fenster, SQLite-Testdaten und Beispielaufrufen auszuführen.&lt;br /&gt;
&lt;br /&gt;
=== Task Variable anlegen ===&lt;br /&gt;
&lt;br /&gt;
Lege in deiner Startup Task eine Task Variable an:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Name !! Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; sollte als global erreichbarer Singleton der Anwendung verwendet werden. In Omnis ist dafür eine Task Variable sinnvoll, weil sie von Fenstern, Objektklassen und zentralen Error-Handlern aus konsistent erreichbar ist. Dadurch gibt es genau eine aktive Sentry-Konfiguration mit einer DSN, einem Status, optionalen Proxy-Daten und gemeinsamen Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im [[#Demo Library|Demo-Projekt]] ist diese Variable in &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; definiert.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung im Startup Task ===&lt;br /&gt;
&lt;br /&gt;
Initialisiere &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; beim Start deiner Anwendung mit der DSN deines Sentry-Projekts:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;&amp;lt;DSN&amp;gt;&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die [[#Demo Library|Demo-Library]] ruft im Startup Task ebenfalls die Initialisierung auf. Quelle: &amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init Sentry on lbs startup&lt;br /&gt;
Do tSentry.$init()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In einer produktiven Anwendung sollte die DSN explizit oder aus einer Konfiguration übergeben werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;https://PUBLIC_KEY@sentry.io/PROJECT_ID&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; Speichere die DSN in einer Datenbank, einer Konfigurationstabelle oder einem Config File. So kann sie pro Kunde, Umgebung oder Installation geändert werden, ohne die Library neu auszuliefern.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Testcall ===&lt;br /&gt;
&lt;br /&gt;
Nach der Initialisierung kann ein erstes Testevent gesendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello World!&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles korrekt eingerichtet ist, erscheint das Event im Sentry-Projekt.&lt;br /&gt;
&lt;br /&gt;
=== Proxy konfigurieren ===&lt;br /&gt;
&lt;br /&gt;
Falls die Anwendung in einem geschützten Netzwerk läuft, kann ein Proxy gesetzt werden. Die Methode befindet sich im Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.iOSentry.$setProxy(&#039;proxy.example.local&#039;,&#039;8080&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die interne Implementierung setzt den Proxy vor dem HTTP-Request:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Configure proxy; needed when sending data out of secured networks&lt;br /&gt;
If not(isclear(iProxyHost))&amp;amp;not(isclear(iProxyPort))&lt;br /&gt;
	HTTPSetProxyServer (iProxyHost,iProxyPort)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sentry aktivieren oder deaktivieren ===&lt;br /&gt;
&lt;br /&gt;
OSentry kann zentral ein- oder ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; Deaktiviere Sentry in der Entwicklungs-Version standardmäßig oder verwende eine separate Entwicklungs-DSN. So landen lokale Tests, Debug-Fehler und absichtlich ausgelöste Exceptions nicht im produktiven Sentry-Projekt.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$setStatus(1)     ## aktiv&lt;br /&gt;
Do tSentry.$setStatus(0)     ## inaktiv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; wird vor dem Senden geprüft:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Check if Sentry is enabled&lt;br /&gt;
If iStatus=0|isclear(iStatus)&lt;br /&gt;
	Quit method 0&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite zeigt die minimale Integration in eine bestehende Omnis-Anwendung.&lt;br /&gt;
&lt;br /&gt;
=== Klassen übernehmen ===&lt;br /&gt;
&lt;br /&gt;
Kopiere &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; in deine Library.&lt;br /&gt;
&lt;br /&gt;
=== Task Variable erstellen ===&lt;br /&gt;
&lt;br /&gt;
In der Startup Task:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Name !! Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sentry initialisieren ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;https://PUBLIC_KEY@sentry.io/PROJECT_ID&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL.$init&amp;lt;/code&amp;gt; delegiert an das Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init of the main sentry object&lt;br /&gt;
Do iOSentry.$init(pDSN)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message senden ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die [[#Demo Library|Demo-Library]] verwendet genau diesen Aufruf im Button &amp;lt;code&amp;gt;Trigger a message&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.message.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exception senden ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== In Sentry prüfen ===&lt;br /&gt;
&lt;br /&gt;
In Sentry sollte anschließend ein neues Event sichtbar sein. Je nach Event-Typ enthält es:&lt;br /&gt;
&lt;br /&gt;
* Message&lt;br /&gt;
* Level&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|User-Kontext]]&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]]&lt;br /&gt;
* Omnis-Kontextinformationen&lt;br /&gt;
&lt;br /&gt;
== Events erfassen ==&lt;br /&gt;
&lt;br /&gt;
OSentryHL ist die empfohlene Einstiegsschicht für Applikationscode. Die Klasse bietet sprechende Methoden für typische Event-Arten und ruft intern &amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
&lt;br /&gt;
=== Message ===&lt;br /&gt;
&lt;br /&gt;
Eine einfache Information wird mit &amp;lt;code&amp;gt;$captureMessage&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello World!&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an Info Message&lt;br /&gt;
Do iOSentry.$captureException(pMessage,3,,&#039;info&#039;,kFalse,,kFalse) Returns code&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Level: &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;&lt;br /&gt;
* Kein [[#Stacktrace und Kontext|Stacktrace]]&lt;br /&gt;
* Kein [[#Tags, Extras und User-Kontext|User Interface]]&lt;br /&gt;
* Geeignet für einfache Statusmeldungen oder technische Hinweise&lt;br /&gt;
&lt;br /&gt;
=== Log ===&lt;br /&gt;
&lt;br /&gt;
Ein Log-Event wird mit &amp;lt;code&amp;gt;$captureLog&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureLog(&#039;Uh oh this is a Log because something went wrong&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a Log Sentry Report&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;Log&#039;,&#039;warning&#039;,1,0,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Level: &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]] aktiv&lt;br /&gt;
* Exception Interface in diesem Wrapper deaktiviert&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|User Interface]] aktiv&lt;br /&gt;
&lt;br /&gt;
=== Generische Exception ===&lt;br /&gt;
&lt;br /&gt;
Eine generische Exception wird mit &amp;lt;code&amp;gt;$captureException&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture a generic Exception&lt;br /&gt;
#Add any custom tags / extras&lt;br /&gt;
Do $cinst.$addTag(&#039;Custom Test Tag&#039;,&#039;Euromnis&#039;)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; || Text, der in Sentry als Message sichtbar ist&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; || Fehlercode oder fachlicher Code&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExcType&amp;lt;/code&amp;gt; || Exception-Typ für Benennung und Gruppierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pLevel&amp;lt;/code&amp;gt; || Sentry-Level&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Gültige Levels:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception ===&lt;br /&gt;
&lt;br /&gt;
SQL-Fehler können mit &amp;lt;code&amp;gt;$captureSQLException&amp;lt;/code&amp;gt; gemeldet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureSQLException(&#039;SQL statement failed&#039;,stat)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Fügt die Datenbank als [[#Tags, Extras und User-Kontext|Tag]] hinzu&lt;br /&gt;
* Fügt SQL-Text als [[#Tags, Extras und User-Kontext|Extra]] hinzu&lt;br /&gt;
* Fügt native Datenbankfehlermeldung als [[#Tags, Extras und User-Kontext|Extra]] hinzu&lt;br /&gt;
* Sendet das Event als &amp;lt;code&amp;gt;SQL-Exception&amp;lt;/code&amp;gt; mit Level &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deprecated Call ===&lt;br /&gt;
&lt;br /&gt;
Veraltete Codepfade können gezielt gemeldet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureDeprecatedCall()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Wrapper eignet sich, um zu erkennen, ob alter Code in produktiven Systemen noch ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
=== Frei konfigurierbares Event ===&lt;br /&gt;
&lt;br /&gt;
Für Sonderfälle gibt es &amp;lt;code&amp;gt;$captureAnything&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureAnything(&#039;Text&#039;,1001,&#039;Custom Type&#039;,&#039;error&#039;,kTrue,kTrue,kTrue)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Capture a generic Sentry Report (max configurability)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Methode bietet maximale Flexibilität. Für wiederkehrende Exception-Typen sollte aber eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; angelegt werden. Siehe [[#Eigene Exceptions standardisieren|04 Eigene Exceptions standardisieren]].&lt;br /&gt;
&lt;br /&gt;
== Eigene Exceptions standardisieren ==&lt;br /&gt;
&lt;br /&gt;
Wenn ein Exception-Typ mehrfach in der Anwendung vorkommt, sollte er nicht überall manuell mit &amp;lt;code&amp;gt;$captureException&amp;lt;/code&amp;gt; aufgebaut werden. Besser ist eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dadurch entsteht eine zentrale, wiederverwendbare Definition für:&lt;br /&gt;
&lt;br /&gt;
* Exception-Typ&lt;br /&gt;
* Sentry-Level&lt;br /&gt;
* Fehlercode&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]]&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]]/[[#Tags, Extras und User-Kontext|User]]/Exception Interface&lt;br /&gt;
&lt;br /&gt;
Die automatisch gesetzten [[#Tags, Extras und User-Kontext|Tags und Extras]] aus &amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; müssen in solchen Wrappern nicht erneut ergänzt werden. Eigene Exception-Methoden setzen nur zusätzliche Werte, die für diesen standardisierten Exception-Typ relevant sind.&lt;br /&gt;
&lt;br /&gt;
=== Warum über OSentryHL? ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ist die Abstraktionsschicht für Applikationscode. Sie kapselt die Details von &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und sorgt dafür, dass Aufrufe in der Anwendung kurz und konsistent bleiben.&lt;br /&gt;
&lt;br /&gt;
Bestehende Beispiele aus &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Empfohlenes Muster ===&lt;br /&gt;
&lt;br /&gt;
Für jeden standardisierten Exception-Typ wird eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; erstellt.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a validation exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Field&#039;,pField)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Invalid Value&#039;,pValue)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,2001,&#039;Validation-Exception&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mögliche Parameter der neuen Methode:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Beispiel !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;Invalid customer number&#039;&amp;lt;/code&amp;gt; || Sentry Message&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pModule&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;Customer&#039;&amp;lt;/code&amp;gt; || Filterbarer Tag&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pField&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;cu_number&#039;&amp;lt;/code&amp;gt; || Diagnoseinformation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pValue&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;ABC&#039;&amp;lt;/code&amp;gt; || Diagnoseinformation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der Applikationscode bleibt dadurch einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureValidationException(&#039;Invalid customer number&#039;,&#039;Customer&#039;,&#039;cu_number&#039;,cu_number)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel: Business Rule Exception ===&lt;br /&gt;
&lt;br /&gt;
Neue Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a business rule violation&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addTag(&#039;Business Rule&#039;,pRuleName)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Details&#039;,pDetails)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aufruf in der Anwendung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureBusinessRuleViolation(&#039;Invoice cannot be posted&#039;,&#039;Invoice&#039;,&#039;PostingAllowed&#039;,&#039;Invoice is missing customer&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel: Integration Exception ===&lt;br /&gt;
&lt;br /&gt;
Neue Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an integration exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Integration&#039;,pSystem)&lt;br /&gt;
Do $cinst.$addTag(&#039;Endpoint&#039;,pEndpoint)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Payload&#039;,pPayload)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Response&#039;,pResponse)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,4001,&#039;Integration-Exception&#039;,&#039;error&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aufruf in der Anwendung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureIntegrationException(&#039;External API request failed&#039;,&#039;ERP&#039;,&#039;/api/customer&#039;,jsonPayload,responseText)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Namenskonventionen ===&lt;br /&gt;
&lt;br /&gt;
Empfehlung für neue Methoden:&lt;br /&gt;
&lt;br /&gt;
* Methodenname beginnt mit &amp;lt;code&amp;gt;$capture&amp;lt;/code&amp;gt;&lt;br /&gt;
* Der fachliche Typ steht im Methodennamen&lt;br /&gt;
* Der Sentry Exception Type ist stabil und ändert sich nicht laufend&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]] sind kurz und filterbar&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]] dürfen länger sein und Diagnoseinformationen enthalten&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureValidationException&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureBusinessRuleViolation&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureIntegrationException&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$capturePermissionViolation&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureConfigurationError&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error Codes ===&lt;br /&gt;
&lt;br /&gt;
Verwende feste Fehlercodes für standardisierte Exception-Typen. Dadurch können Events in Sentry besser gefiltert und wiedererkannt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Code !! Exception Type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Validation-Exception&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Business-Rule-Violation&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Integration-Exception&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;5001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Configuration-Error&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wann nicht standardisieren? ===&lt;br /&gt;
&lt;br /&gt;
Nicht jeder Einzelfall braucht eine eigene Methode. Für einmalige technische Tests oder sehr spezielle Fälle reicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald ein Exception-Typ aber mehrfach vorkommt oder fachlich relevant ist, sollte er als eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
== Tags, Extras und User-Kontext ==&lt;br /&gt;
&lt;br /&gt;
Tags, Extras und User-Kontext reichern Sentry-Events mit zusätzlichen Informationen an. Diese Informationen helfen beim Filtern, Gruppieren und Analysieren.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-tags.png|900px|Sentry Tags und User-Kontext]]&lt;br /&gt;
&lt;br /&gt;
=== Tags ===&lt;br /&gt;
&lt;br /&gt;
Tags sind kurze, filterbare Werte.&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* Datenbank&lt;br /&gt;
* Kunde&lt;br /&gt;
* Modul&lt;br /&gt;
* Umgebung&lt;br /&gt;
* Error Code&lt;br /&gt;
* Omnis-Version&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add a Tag to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addTag(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Adds a tag to the next request processed&lt;br /&gt;
Do iTagList.$add(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$addTag(&#039;Module&#039;,&#039;Invoice&#039;)&lt;br /&gt;
Do tSentry.$addTag(&#039;Customer&#039;,&#039;10001&#039;)&lt;br /&gt;
Do tSentry.$captureException(&#039;Invoice posting failed&#039;,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Extras ===&lt;br /&gt;
&lt;br /&gt;
Extras sind Detailinformationen, die nicht primär zum Filtern gedacht sind.&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* SQL-Text&lt;br /&gt;
* Native Datenbankfehlermeldung&lt;br /&gt;
* Payload&lt;br /&gt;
* Response Body&lt;br /&gt;
* interne IDs&lt;br /&gt;
* zusätzliche Debug-Informationen&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add an Extra to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addExtra(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Adds extra information to the next request being processed&lt;br /&gt;
Do iExtraList.$add(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel aus der SQL Exception:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Automatische Tags ===&lt;br /&gt;
&lt;br /&gt;
Die folgenden Tags werden bei jedem Event automatisch von &amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; ergänzt. Sie müssen bei eigenen Exceptions nicht erneut gesetzt werden. Eigene Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; sollten nur zusätzliche, fachlich oder technisch relevante Tags hinzufügen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; fügt mehrere Tags automatisch hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add static tags&lt;br /&gt;
Do iTagList.$add(&#039;Omnisversion&#039;,sys(1))&lt;br /&gt;
Calculate systemversionRow as systemversion()&lt;br /&gt;
Do iTagList.$add(&#039;Plattform&#039;,con(sys(8),pick(systemversionRow.server,&#039;&#039;,&#039; SRV&#039;)))&lt;br /&gt;
Do iTagList.$add(&#039;OS Version&#039;,con(systemversionRow.major,&#039;.&#039;,systemversionRow.minor,&#039;.&#039;,systemversionRow.build))&lt;br /&gt;
Do iTagList.$add(&#039;error_code&#039;,pErrorCode)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Automatisch gesendete Tags:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tag !! Herkunft !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Omnisversion&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;sys(1)&amp;lt;/code&amp;gt; || Zeigt, mit welcher Omnis-Version das Event erzeugt wurde&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Plattform&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;sys(8)&amp;lt;/code&amp;gt; und Server-Flag aus &amp;lt;code&amp;gt;systemversion()&amp;lt;/code&amp;gt; || Unterscheidet Plattform und Server Runtime&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OS Version&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;systemversionRow.major/minor/build&amp;lt;/code&amp;gt; || Zeigt die Betriebssystemversion&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;error_code&amp;lt;/code&amp;gt; || Parameter &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; || Verbindet das Event mit dem übergebenen Fehlercode&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Beispiel für eine eigene Exception: Der Wrapper muss nicht erneut &amp;lt;code&amp;gt;Omnisversion&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;OS Version&amp;lt;/code&amp;gt; setzen. Er ergänzt nur das, was für diesen Exception-Typ zusätzlich hilfreich ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addTag(&#039;Business Rule&#039;,pRuleName)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Automatische Extras ===&lt;br /&gt;
&lt;br /&gt;
Auch die folgenden Extras werden bei jedem Event automatisch ergänzt. Bei eigenen Exceptions müssen nur zusätzliche Extras gesetzt werden, zum Beispiel ein SQL-Statement, ein Payload oder fachliche Zusatzdaten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; fügt offene Fenster, offene Reports und die aktuelle Printfile hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Static extra 1: All open windows&lt;br /&gt;
Do $root.$iwindows.$makelist($ref.$name) Returns nameList&lt;br /&gt;
For i from 1 to nameList.$linecount step 1&lt;br /&gt;
	Calculate windows as con(windows,&#039;, &#039;,nameList.[i].1)&lt;br /&gt;
End For&lt;br /&gt;
Calculate windows as right(windows,len(windows)-2)&lt;br /&gt;
Do iExtraList.$add(&#039;Open Windows&#039;,windows)&lt;br /&gt;
&lt;br /&gt;
# Static extra 2: All open reports&lt;br /&gt;
Do $root.$ireports.$makelist($ref.$name) Returns nameList&lt;br /&gt;
For i from 1 to nameList.$linecount step 1&lt;br /&gt;
	Calculate reports as con(reports,&#039;, &#039;,nameList.[i].1)&lt;br /&gt;
End For&lt;br /&gt;
Calculate reports as right(reports,len(reports)-2)&lt;br /&gt;
Do iExtraList.$add(&#039;Open Reports&#039;,reports)&lt;br /&gt;
Do iExtraList.$add(&#039;Current Printfile&#039;,$root.$prefs.$printfile)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Automatisch gesendete Extras:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Extra !! Herkunft !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Open Windows&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$iwindows.$makelist($ref.$name)&amp;lt;/code&amp;gt; || Zeigt, welche Fenster im Moment des Events offen waren&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Open Reports&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$ireports.$makelist($ref.$name)&amp;lt;/code&amp;gt; || Zeigt, welche Reports im Moment des Events offen waren&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Current Printfile&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$prefs.$printfile&amp;lt;/code&amp;gt; || Zeigt die aktuell gesetzte Printfile&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Beispiel für zusätzliche Extras in einem eigenen Wrapper:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addExtra(&#039;Payload&#039;,pPayload)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Response&#039;,pResponse)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,4001,&#039;Integration-Exception&#039;,&#039;error&#039;,1,1,1) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== User-Kontext ===&lt;br /&gt;
&lt;br /&gt;
Der User-Kontext ordnet ein Event einem betroffenen Benutzer zu. In Sentry erscheint dadurch ein eigener User-Bereich, und Events können nach Benutzer gefiltert oder gruppiert werden. Das ist besonders hilfreich, wenn ein Fehler nur bei einzelnen Kunden, Arbeitsplätzen oder Benutzerkonten auftritt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; unterstützt drei User-Felder:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feld !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt; || stabile interne Benutzer-ID oder Kundennummer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;username&amp;lt;/code&amp;gt; || lesbarer Benutzername&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;email&amp;lt;/code&amp;gt; || E-Mail-Adresse, falls sie übertragen werden darf&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der User-Kontext wird nur in das Event geschrieben, wenn das User Interface beim Capture-Aufruf aktiviert ist. Die Standardmethode &amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; hat &amp;lt;code&amp;gt;pUserInterface&amp;lt;/code&amp;gt; standardmäßig auf &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt;. Einzelne High-Level-Methoden können das bewusst deaktivieren, zum Beispiel &amp;lt;code&amp;gt;$captureMessage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; kann User-Daten an das Event anhängen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Sets userinformation for the next request being processed&lt;br /&gt;
Calculate iUserID as pID&lt;br /&gt;
Calculate iUserName as pName&lt;br /&gt;
Calculate iUserEmail as pEmail&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das User Interface wird so generiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Create user data row&lt;br /&gt;
Do UserdataRow.$define(id,email,username)&lt;br /&gt;
&lt;br /&gt;
Calculate UserdataRow.id as iUserID&lt;br /&gt;
Calculate UserdataRow.email as iUserEmail&lt;br /&gt;
Calculate UserdataRow.username as iUserName&lt;br /&gt;
&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;user&#039;,&#039;&#039;)&lt;br /&gt;
Do JSON.$setobject(&#039;user&#039;,UserdataRow)&lt;br /&gt;
&lt;br /&gt;
Calculate jsonString as OJSON.$formatjson(JSON.$getjson())&lt;br /&gt;
&lt;br /&gt;
Quit method jsonString&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die aktuelle Demo-Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; verwendet feste Testdaten. Quelle: &amp;lt;code&amp;gt;OSentryHL.$setUser&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Set the User which should be linked to the Sentry Issue&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte diese Methode angepasst und parametrisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(pUserID,pUserName,pUserEmail)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Empfohlen ist, den User nach Login oder beim Wechsel des aktiven Benutzers zentral zu setzen. Bei anonymen oder sensiblen Installationen kann statt Name und E-Mail auch nur eine interne ID oder ein pseudonymisierter Wert verwendet werden.&lt;br /&gt;
&lt;br /&gt;
=== Datenschutz ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #72777d; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Datenschutz:&#039;&#039;&#039; Prüfe vor produktiver Nutzung, welche Daten an Sentry gesendet werden. Besonders kritisch sind personenbezogene Daten, SQL-Statements, Zugangsdaten, Tokens und interne Pfade.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Besonders kritisch sind:&lt;br /&gt;
&lt;br /&gt;
* personenbezogene Daten&lt;br /&gt;
* Kundendaten&lt;br /&gt;
* SQL-Statements mit Werten&lt;br /&gt;
* Zugangsdaten&lt;br /&gt;
* Tokens&lt;br /&gt;
* interne Pfade&lt;br /&gt;
&lt;br /&gt;
Tags und Extras sollten so gestaltet werden, dass sie für die Fehleranalyse hilfreich sind, aber keine unnötigen sensiblen Daten übertragen.&lt;br /&gt;
&lt;br /&gt;
== Stacktrace und Kontext ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; erzeugt einen Omnis-spezifischen Stacktrace und übergibt ihn an Sentry. Dadurch sieht man in Sentry nicht nur eine Fehlermeldung, sondern auch Klassen, Methoden, Zeilen und Variablenkontext. Ergänzende Informationen zu [[#Tags, Extras und User-Kontext|Tags, Extras und User-Kontext]] stehen auf der separaten Kontext-Seite.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-stack.png|900px|Sentry Stacktrace mit Omnis-Kontext]]&lt;br /&gt;
&lt;br /&gt;
=== Stack lesen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateStacktraceInterface&amp;lt;/code&amp;gt; verwendet &amp;lt;code&amp;gt;sys(192)&amp;lt;/code&amp;gt;, um den aktuellen Omnis-Stack zu lesen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Clean up the Stacklist (remove OSentry classes from the stack)&lt;br /&gt;
Do sys(192) Returns sys192List&lt;br /&gt;
For sys192List.$line from 1 to sys192List.$linecount step 1&lt;br /&gt;
	Set reference class to sys192List.classitem&lt;br /&gt;
	If pos(&#039;OSentry&#039;,class.$name)&amp;gt;0|pos(&#039;OSentryHL&#039;,class.$name)&amp;gt;0&lt;br /&gt;
		Do sys192List.[sys192List.$line].$selected.$assign(kTrue)&lt;br /&gt;
	End If&lt;br /&gt;
End For&lt;br /&gt;
Do sys192List.$remove(kListDeleteSelected)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Interne Frames von &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; werden entfernt, damit in Sentry die fachlich relevanten Stellen sichtbar bleiben.&lt;br /&gt;
&lt;br /&gt;
=== SQL-Error Frames entfernen ===&lt;br /&gt;
&lt;br /&gt;
Bestimmte interne SQL-Fehlerframes werden ebenfalls entfernt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Remove some other classes which we do not want to display&lt;br /&gt;
If sys192List.1.method=&#039;$sqlerror&#039;&lt;br /&gt;
	Do sys192List.$remove(1)&lt;br /&gt;
Else If sys192List.1.method=&#039;$statementerror&#039;&lt;br /&gt;
	Do sys192List.$remove(1)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frames erzeugen ===&lt;br /&gt;
&lt;br /&gt;
Für jeden Stack-Eintrag werden Funktion, Zeilennummer und Kontextzeile erzeugt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Loop through every item on the omnis stack&lt;br /&gt;
For sys192List.$line from 1 to sys192List.$linecount step 1&lt;br /&gt;
	Set reference class to sys192List.classitem&lt;br /&gt;
	Calculate className as class.$name&lt;br /&gt;
	&lt;br /&gt;
	# Create the content row&lt;br /&gt;
	Do contentRow.$define(vars,function,pre_context,context_line,lineno,filename,post_context)&lt;br /&gt;
	Calculate contentRow.lineno as sys192List.line&lt;br /&gt;
	Calculate contentRow.filename as testFileName&lt;br /&gt;
	Calculate contentRow.context_line as sys192List.linetext&lt;br /&gt;
	If isclear(sys192List.object)&lt;br /&gt;
		Calculate contentRow.function as con(className,&#039;.&#039;,sys192List.method) ## If it&#039;s a class method&lt;br /&gt;
	Else&lt;br /&gt;
		Calculate contentRow.function as con(className,&#039;.&#039;,sys192List.object,&#039;.&#039;,sys192List.method) ## If it&#039;s a method of an object of a class (e.g. Headedlist)&lt;br /&gt;
	End If&lt;br /&gt;
	Do contentList.$add(contentRow)&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablen aufnehmen ===&lt;br /&gt;
&lt;br /&gt;
Pro Stackframe werden Instance Variablen und Parameter gesammelt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Get all iVars&lt;br /&gt;
Do varList.$define(name,value)&lt;br /&gt;
Set reference class to sys192List.inst&lt;br /&gt;
Do $cinst.$getVars(&#039;ivars&#039;,class) Returns varList&lt;br /&gt;
&lt;br /&gt;
# Get all params&lt;br /&gt;
Calculate paramList as sys192List.params&lt;br /&gt;
For paramList.$line from 1 to paramList.$linecount step 1&lt;br /&gt;
	If not(paramList.value=&#039;(Not empty)&#039;)&lt;br /&gt;
		Do varList.$add(paramList.name,paramList.value)&lt;br /&gt;
	Else&lt;br /&gt;
		Do varList.$add(paramList.name,&#039;(Not empty)&#039;)&lt;br /&gt;
	End If&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pre- und Post-Context ===&lt;br /&gt;
&lt;br /&gt;
OSentry fügt Methodenzeilen vor und nach der aktuellen Zeile hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Pre Context (all method lines before the error occured)&lt;br /&gt;
Set reference method to sys192List.methoditem&lt;br /&gt;
Do precontextList.$define(line)&lt;br /&gt;
For i from 1 to sys192List.line-1 step 1&lt;br /&gt;
	Do precontextList.$add(method.$methodlines.[i].$text)&lt;br /&gt;
End For&lt;br /&gt;
&lt;br /&gt;
# Post Context (all method lines after the error occured&lt;br /&gt;
Do postcontextList.$define(line)&lt;br /&gt;
For i from sys192List.line+1 to method.$methodlines.$count step 1&lt;br /&gt;
	Do postcontextList.$add(method.$methodlines.[i].$text)&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablentypen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$getVars&amp;lt;/code&amp;gt; unterstützt Basisvariablen, Rows und Lists.&lt;br /&gt;
&lt;br /&gt;
Basisvariablen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
If varType=&#039;char&#039;|varType=&#039;boolean&#039;|varType=&#039;integer&#039;|varType=&#039;number&#039;|varType=&#039;date&#039;&lt;br /&gt;
	Calculate varContent as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	Do varList.$add(varName,varContent)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Else If varType=&#039;row&#039;&lt;br /&gt;
	Calculate varRow as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	If varRow.$colcount=0&lt;br /&gt;
		Do varList.$add(varName,&#039;(Empty)&#039;)&lt;br /&gt;
	Else&lt;br /&gt;
		For Z2 from 1 to varRow.$colcount step 1&lt;br /&gt;
			Calculate varContent as con(varContent,varRow.$cols.[Z2].$name,&#039;: &#039;,varRow.[Z2],&#039;, &#039;)&lt;br /&gt;
		End For&lt;br /&gt;
		Do varList.$add(varName,varContent)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lists:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Else If varType=&#039;list&#039;&lt;br /&gt;
	Calculate varListType as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	Calculate varContent as con(&#039;Colcount: &#039;,varListType.$colcount,&#039;, &#039;,&#039;Linecount: &#039;,varListType.$linecount,&#039;, &#039;,&#039;Current Line: &#039;,varListType.$line)&lt;br /&gt;
	If varListType.$linecount=0&amp;amp;varListType.$line=0&amp;amp;varListType.$colcount=0&lt;br /&gt;
		Do varList.$add(varName,&#039;(Empty)&#039;)&lt;br /&gt;
		Calculate varContent as &#039;&#039;&lt;br /&gt;
	Else&lt;br /&gt;
		For Z3 from 1 to varListType.$colcount step 1&lt;br /&gt;
			Calculate colName as varListType.$cols.[Z3].$name&lt;br /&gt;
			Calculate varContent as con(varContent,&#039;  &#039;,colName,&#039;: &#039;,varListType.[colName])&lt;br /&gt;
		End For&lt;br /&gt;
		Do varList.$add(varName,varContent)&lt;br /&gt;
		Calculate varContent as &#039;&#039;&lt;br /&gt;
	End If&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
&lt;br /&gt;
Stacktrace und Variablenkontext sind sehr hilfreich, können aber sensible Daten enthalten. Vor produktiver Nutzung sollte geprüft werden, ob bestimmte Variablen anonymisiert oder ausgeschlossen werden müssen.&lt;br /&gt;
&lt;br /&gt;
== Interne Architektur ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite beschreibt die produktiv relevanten Klassen &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Klassenübersicht ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Rolle&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; || High-Level-Adapter für Applikationscode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; || Low-Level-Adapter für JSON, [[#Stacktrace und Kontext|Stacktrace]] und HTTP&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Startup und Beispiel für Initialisierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Code für [[#Stacktrace und Kontext|Stacktrace]]-Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-DB Initialisierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt; || SQLite Session für [[#Demo Library|Demo]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Empfohlener Aufrufweg ===&lt;br /&gt;
&lt;br /&gt;
Applikationscode sollte &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; verwenden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; delegiert anschließend an &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ablauf eines Events ===&lt;br /&gt;
&lt;br /&gt;
# Applikationscode ruft Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; fügt bei Bedarf [[#Tags, Extras und User-Kontext|Tags und Extras]] hinzu.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ruft &amp;lt;code&amp;gt;iOSentry.$captureException(...)&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; prüft, ob Sentry aktiv ist.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; erzeugt JSON.&lt;br /&gt;
# [[#Stacktrace und Kontext|Stacktrace]], Exception Interface und [[#Tags, Extras und User-Kontext|User Interface]] werden optional ergänzt.&lt;br /&gt;
# HTTP Header und Sentry Auth Header werden erstellt.&lt;br /&gt;
# JSON wird per HTTPS an Sentry gesendet.&lt;br /&gt;
# Bei Erfolg werden [[#Tags, Extras und User-Kontext|Tags und Extras]] geleert.&lt;br /&gt;
# Bei Fehler wird der JSON Report lokal gespeichert.&lt;br /&gt;
&lt;br /&gt;
=== DSN Parsing ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$init&amp;lt;/code&amp;gt; zerlegt die DSN:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Parse the DSN into Public Key, Host and Project ID&lt;br /&gt;
If len(pDSN)&amp;gt;5&lt;br /&gt;
	Calculate iDSN as pDSN&lt;br /&gt;
	Calculate part1 as strtok(&#039;iDSN&#039;,&#039;@&#039;)&lt;br /&gt;
	Calculate iProtocol as strtok(&#039;part1&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iProtocol as left(iProtocol,len(iProtocol)-1)&lt;br /&gt;
	Do strtok(&#039;part1&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iPubKey as strtok(&#039;part1&#039;,&#039;:&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Calculate iHost as strtok(&#039;iDSN&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iProID as iDSN&lt;br /&gt;
	&lt;br /&gt;
	#Save the values for the next startup&lt;br /&gt;
	Calculate $cclass.$ivardefs.iPubKey.$objinitval as con(&#039;&amp;quot;&#039;,iPubKey,&#039;&amp;quot;&#039;)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iHost.$objinitval as con(&#039;&amp;quot;&#039;,iHost,&#039;&amp;quot;&#039;)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iProID.$objinitval as con(&#039;&amp;quot;&#039;,iProID,&#039;&amp;quot;&#039;)&lt;br /&gt;
End If&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== JSON-Erzeugung ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; ist die zentrale Methode für den Payload. Sie setzt unter anderem:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;event_id&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;logger&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;platform&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;culprit&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;timestamp&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sdk&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;message&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;level&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;tags&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;extra&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;exception&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;stacktrace&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auszug:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add all required fields (those are required from the API)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;event_id&#039;,$cinst.$generateUUID()) ## auto generated UUID 4&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;logger&#039;,logger)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;platform&#039;,platform)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;culprit&#039;,culprit)&lt;br /&gt;
#Do JSON.$addmember(&#039;&#039;,&#039;release&#039;,release)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;timestamp&#039;,timestamp)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;sdk&#039;,&#039;&#039;)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;message&#039;,pErrorText)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;level&#039;,pLevel)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;tags&#039;,&#039;&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== HTTP-Kommunikation ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; sendet den erzeugten JSON-Payload an Sentry:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Generate HTTP Auth header&lt;br /&gt;
Begin text block&lt;br /&gt;
Text:Sentry sentry_version=7,&lt;br /&gt;
Text:sentry_timestamp=[$cinst.$getUnixTimestamp()],&lt;br /&gt;
Text:sentry_key=[iPubKey],&lt;br /&gt;
Text:sentry_client=omnis/1.0&lt;br /&gt;
End text block&lt;br /&gt;
Get text block auth&lt;br /&gt;
&lt;br /&gt;
#Generate header list&lt;br /&gt;
Calculate Host as &#039;sentry.io&#039;&lt;br /&gt;
Calculate Url as con(&#039;/api/&#039;,iProID,&#039;/store/&#039;)&lt;br /&gt;
Do HdrList.$define(wert,name)&lt;br /&gt;
Do HdrList.$add(&#039;User-Agent&#039;,&#039;omnis/1.0&#039;)&lt;br /&gt;
Do HdrList.$add(&#039;Content-Type&#039;,&#039;application/json&#039;)&lt;br /&gt;
Do HdrList.$add(&#039;Content-Length&#039;,binlength(json))&lt;br /&gt;
Do HdrList.$add(&#039;X-Sentry-Auth&#039;,auth)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anschließend wird der Request über &amp;lt;code&amp;gt;HTTPPost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HTTPSend&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;HTTPRead&amp;lt;/code&amp;gt; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
=== Fehlerbehandlung beim Senden ===&lt;br /&gt;
&lt;br /&gt;
Wenn der Socket nicht geöffnet werden kann:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPPost (Host,Url,,HdrList,443,kTrue,kTrue) Returns Socket&lt;br /&gt;
If Socket&amp;lt;0&lt;br /&gt;
	#Error when opening connection -&amp;gt; save json as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,con(&#039;Error &#039;,Socket,&#039; when performing HTTPPost&#039;))&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -1&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn das Senden fehlschlägt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPSend (Socket,json) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0&lt;br /&gt;
	# Error while sending data -&amp;gt; save json as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,con(&#039;Erorr &#039;,byteCount,&#039; when performing HTTPSend&#039;))&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -2&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn die Antwort nicht erfolgreich ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPRead (Socket,Buffer) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0|not(pos(&#039;200 OK&#039;,Buffer))&lt;br /&gt;
	# JSON may be corrupted or contains errors -&amp;gt; save json and the buffer as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,Buffer)&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -3&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Lokales Speichern ===&lt;br /&gt;
&lt;br /&gt;
Bei Fehlern wird der JSON Report lokal im Omnis-Installationsordner gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Writes the json and the http buffer to a file in the omnis installation folder&lt;br /&gt;
Calculate path as sys(115)&lt;br /&gt;
Calculate filename as con(&#039;Sentryreport_&#039;,$cinst.$getUnixTimestamp(),&#039;.json&#039;)&lt;br /&gt;
Do fOP.$createfile(con(path,filename)) Returns err&lt;br /&gt;
Do fOP.$writecharacter(kUniTypeUTF8,pJSON) Returns err&lt;br /&gt;
If not(isclear(pBuffer))&lt;br /&gt;
	Do fOP.$writecharacter(kUniTypeUTF8,con(kCr,pBuffer),kTrue) Returns err&lt;br /&gt;
End If&lt;br /&gt;
Do fOP.$closefile()&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cleanup ===&lt;br /&gt;
&lt;br /&gt;
Nach erfolgreichem Senden werden [[#Tags, Extras und User-Kontext|Tags und Extras]] gelöscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Clears all extras and tags =&amp;gt; to be used after a sentry request has successfully been sent&lt;br /&gt;
Do iTagList.$clear()&lt;br /&gt;
Do iExtraList.$clear()&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Demo Library ==&lt;br /&gt;
&lt;br /&gt;
Die Demo-Library zeigt, wie &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; initialisiert wird und wie verschiedene [[#Events erfassen|Event-Typen]] aus einer Omnis-Oberfläche heraus an Sentry gesendet werden.&lt;br /&gt;
&lt;br /&gt;
=== Bestandteile ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; || Initialisiert Sentry, SQLite und öffnet das Demo-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; || Demo-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt; || Erzeugt Demo-Stack für Exception&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; || Erstellt SQLite-Demo-Datenbank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt; || SQLite Session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; || Low-Level-Sentry-Adapter&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; || High-Level-Sentry-Adapter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt; initialisiert Sentry, baut eine SQLite Session auf und öffnet das Demo-Fenster. Quelle: &amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init Sentry on lbs startup&lt;br /&gt;
Do tSentry.$init()&lt;br /&gt;
&lt;br /&gt;
#SQLite Session init&lt;br /&gt;
Do $objects.OSLSession.$newref() Returns tOSLSession&lt;br /&gt;
#Calculate tOSLSession.$opencreate as kTrue&lt;br /&gt;
Calculate workingDir as tODatabaseHandler.$getWorkingDir()&lt;br /&gt;
Do con(workingDir,&#039;Sentry_Test.db&#039;) Returns dbLocation&lt;br /&gt;
Do tOSLSession.$logon(dbLocation,&#039;&#039;,&#039;&#039;,&#039;slsession&#039;) Returns #F&lt;br /&gt;
&lt;br /&gt;
#Open Test Window&lt;br /&gt;
Do $windows.FSY_Demo.$openonce(&#039;*&#039;)&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Demo-Fenster ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; enthält folgende Bereiche:&lt;br /&gt;
&lt;br /&gt;
* DSN Configuration&lt;br /&gt;
* DB Status&lt;br /&gt;
* Actions&lt;br /&gt;
&lt;br /&gt;
Wichtige Felder:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feld !! Datenanbindung&lt;br /&gt;
|-&lt;br /&gt;
| DSN || &amp;lt;code&amp;gt;iDSN&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Host || &amp;lt;code&amp;gt;tSentry.iOSentry.iHost&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Public Key || &amp;lt;code&amp;gt;tSentry.iOSentry.iPubKey&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Project ID || &amp;lt;code&amp;gt;tSentry.iOSentry.iProID&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| DB Status || &amp;lt;code&amp;gt;iCurrentDBStatus&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Datei:Demo-window.svg|850px|Demo-Fenster der OSentry Library]]&lt;br /&gt;
&lt;br /&gt;
=== DSN setzen ===&lt;br /&gt;
&lt;br /&gt;
Die DSN wird im Feld &amp;lt;code&amp;gt;iDSN&amp;lt;/code&amp;gt; erfasst. Der Button &amp;lt;code&amp;gt;Set DSN&amp;lt;/code&amp;gt; ruft anschließend &amp;lt;code&amp;gt;tSentry.$init(iDSN)&amp;lt;/code&amp;gt; auf. Nach dem Setzen werden Public Key, Host und Project ID aus der DSN gelesen und in den darunterliegenden Feldern angezeigt.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Demo-dsn.svg|850px|DSN-Konfiguration im Demo-Fenster]]&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Set DSN&amp;lt;/code&amp;gt; initialisiert Sentry mit der eingegebenen DSN. Quelle: &amp;lt;code&amp;gt;FSY_Demo.setDSN.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$init(iDSN)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iDSN.$objinitval as con(kSq,iDSN,kSq)&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$showmessage(&#039;DSN set and Sentry initialized!&#039;,&#039;Info&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$redraw()&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== DB Status anzeigen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FSY_Demo.$displayDBState&amp;lt;/code&amp;gt; zeigt, ob die SQLite Session verbunden ist. Quelle: &amp;lt;code&amp;gt;FSY_Demo.$displayDBState&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tOSLSession.$state Returns dbState&lt;br /&gt;
If dbState=&#039;kSessionStateLoggedOff&#039;&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Logged Off&#039;&lt;br /&gt;
Else If dbState=&#039;kSessionStateLoggedOn&#039;&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Logged On&#039;&lt;br /&gt;
Else&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Unkown DB State&#039;&lt;br /&gt;
End If&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$redraw()&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Demo-Datenbank erstellen ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Create Database&amp;lt;/code&amp;gt; ruft &amp;lt;code&amp;gt;ODatabaseHandler.$DBFirstInit&amp;lt;/code&amp;gt; auf. Quelle: &amp;lt;code&amp;gt;FSY_Demo.createDB.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Setup the DB&lt;br /&gt;
	Do tODatabaseHandler.$DBFirstInit() Returns err&lt;br /&gt;
	If err=0&lt;br /&gt;
		Do $cinst.$showmessage(&#039;DB successfully created!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Else&lt;br /&gt;
		Do $cinst.$showmessage(&#039;Error while creating the DB. Make sure that the DB does not already exist.&#039;,&#039;Info&#039;)&lt;br /&gt;
	End If&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$displayDBState()&lt;br /&gt;
	&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Datenbank wird im Arbeitsverzeichnis der Library angelegt. Quelle: &amp;lt;code&amp;gt;ODatabaseHandler.$getWorkingDir&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Quit method con(FileOps.$parentdir($clib.$pathname),pathsep())&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Demo-DB enthält unter anderem:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;dperson&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;drelease&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;dvcs&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a message&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.message.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Log auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a log&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.log.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureLog(&#039;Uh oh this is a Log because something went wrong&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exception auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger an exception&amp;lt;/code&amp;gt; bereitet eine Row und eine List vor und ruft anschließend &amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt; auf. Quelle: &amp;lt;code&amp;gt;FSY_Demo.exception.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do iDummyRow.$define(id,name)&lt;br /&gt;
	Calculate iDummyRow.id as 22&lt;br /&gt;
	Calculate iDummyRow.name as &#039;Tom&#039;&lt;br /&gt;
	&lt;br /&gt;
	Do iDummyList.$define(id,weekday)&lt;br /&gt;
	Do iDummyList.$add(1,&#039;Monday&#039;)&lt;br /&gt;
	Do iDummyList.$add(2,&#039;Tuesday&#039;)&lt;br /&gt;
	Do iDummyList.$add(3,&#039;Wednesday&#039;)&lt;br /&gt;
	Do iDummyList.$add(4,&#039;Thursday&#039;)&lt;br /&gt;
	Do iDummyList.$add(5,&#039;Friday&#039;)&lt;br /&gt;
	Do iDummyList.$add(6,&#039;Saturday&#039;)&lt;br /&gt;
	Do iDummyList.$add(7,&#039;Sunday&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Calculate iDummyList.$line as 5&lt;br /&gt;
	&lt;br /&gt;
	Do iODummy.$dummyMethod(&#039;Important Value&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt; sendet die Exception. Quelle: &amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#In here is some logic&lt;br /&gt;
#This logic would produce an error&lt;br /&gt;
#We send all this information to Sentry&lt;br /&gt;
&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&lt;br /&gt;
Quit method 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deprecated Call auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a deprecated call&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.deprecatedCall.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureDeprecatedCall()&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception Button ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Trigger an SQLException&amp;lt;/code&amp;gt; ist im Export vorhanden, enthält aber noch keinen fertigen Demo-Code. Quelle: &amp;lt;code&amp;gt;FSY_Demo.sqlException.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Code need&#039;s to be written&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Dokumentation der SQL-Erfassung siehe [[#Events erfassen|03 Events erfassen]].&lt;br /&gt;
&lt;br /&gt;
== API Reference ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite dokumentiert die produktiv relevanten Methoden von &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== OSentryHL ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ist die empfohlene Klasse für Applikationscode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$init(pDSN)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Initialisiert das interne &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;-Objekt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init of the main sentry object&lt;br /&gt;
Do iOSentry.$init(pDSN)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureMessage(pMessage)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet eine einfache Info-Message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an Info Message&lt;br /&gt;
Do iOSentry.$captureException(pMessage,3,,&#039;info&#039;,kFalse,,kFalse) Returns code&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureException(pErrorText,pErrorCode,pExcType,pLevel)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet eine generische Exception.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture a generic Exception&lt;br /&gt;
#Add any custom tags / extras&lt;br /&gt;
Do $cinst.$addTag(&#039;Custom Test Tag&#039;,&#039;Euromnis&#039;)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureAnything(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet ein frei konfigurierbares Event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Capture a generic Sentry Report (max configurability)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hinweis: Der Parameter ist im Export als &amp;lt;code&amp;gt;pStacktraveInterface&amp;lt;/code&amp;gt; geschrieben.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureLog(pErrorText)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet ein Log-Event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a Log Sentry Report&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;Log&#039;,&#039;warning&#039;,1,0,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureDeprecatedCall()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Meldet die Ausführung eines veralteten Codepfads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureSQLException(pErrorText,pStat)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Meldet einen SQL-Fehler mit SQL-Text und nativer Datenbankfehlermeldung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addTag(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt einen Tag für das nächste Event hinzu.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add a Tag to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addTag(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addExtra(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt ein Extra für das nächste Event hinzu.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add an Extra to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addExtra(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setStatus(pStatus)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Aktiviert oder deaktiviert Sentry.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Toggels Sentry on or off&lt;br /&gt;
Do iOSentry.$setStatus(pStatus)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setUser()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt im Export feste [[#Demo Library|Demo]]-Userdaten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Set the User which should be linked to the Sentry Issue&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte diese Methode parametrisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== OSentry ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; ist die Low-Level-Klasse für Payload-Erzeugung und Versand.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$init(pDSN)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parst die DSN in Protokoll, Public Key, Host und Project ID.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraceInterface,pUserInterface,pExceptionInterface)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt JSON, sendet es an Sentry und behandelt Fehlerfälle.&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Default !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; ||  || Message&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; ||  || Fehlercode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExcType&amp;lt;/code&amp;gt; ||  || Exception-Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pLevel&amp;lt;/code&amp;gt; ||  || &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pStacktraceInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || [[#Stacktrace und Kontext|Stacktrace]] senden&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pUserInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || [[#Tags, Extras und User-Kontext|User-Kontext]] senden&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExceptionInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || Exception Interface senden&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateJson(...)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den Sentry JSON Payload als Binary.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateStacktraceInterface(pCulprit)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den Omnis-[[#Stacktrace und Kontext|Stacktrace]] inklusive Variablen und Kontextzeilen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateExceptionInterface(pType,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt das Sentry Exception Interface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Generate Row to store in the JSON&lt;br /&gt;
Do exceptionRow.$define(type,value,stacktrace)&lt;br /&gt;
Calculate exceptionRow.type as pType&lt;br /&gt;
Calculate exceptionRow.value as pValue&lt;br /&gt;
Calculate exceptionRow.stacktrace as &#039;sentry.interfaces.stacktrace&#039; ## Tells the exception interface that a stacktrace is passed aswell&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateUserInterface()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den [[#Tags, Extras und User-Kontext|User-Kontext]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addTag(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt einen Tag zur internen Tag-Liste hinzu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addExtra(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt ein Extra zur internen Extra-Liste hinzu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$clearList()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Leert [[#Tags, Extras und User-Kontext|Tags und Extras]] nach einem Request.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setUserData(pID,pName,pEmail)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt Userdaten für den nächsten Request.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setProxy(pProxyHost,pProxyPort)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt Proxy-Informationen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setStatus(pStatus)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt den Sentry-Status.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Toggels Sentry Reports on or off&lt;br /&gt;
Calculate iStatus as pStatus&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$writeJSON(pJSON,pBuffer)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Schreibt fehlgeschlagene Reports lokal in eine Datei.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$getUnixTimestamp()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Gibt den aktuellen UNIX Timestamp zurück.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateUUID()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt eine UUID für die Sentry Event ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Genereates a UUID for the issue id&lt;br /&gt;
Quit method OW3.$makeuuid(kFalse)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Es erscheinen keine Events in Sentry ===&lt;br /&gt;
&lt;br /&gt;
Prüfe zuerst, ob Sentry aktiv ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$setStatus(1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; beendet sich sofort, wenn der Status &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; oder leer ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Check if Sentry is enabled&lt;br /&gt;
If iStatus=0|isclear(iStatus)&lt;br /&gt;
	Quit method 0&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Die DSN ist falsch ===&lt;br /&gt;
&lt;br /&gt;
Prüfe, ob die DSN korrekt aus Sentry kopiert wurde. &amp;lt;code&amp;gt;OSentry.$init&amp;lt;/code&amp;gt; erwartet eine DSN, aus der Public Key, Host und Project ID gelesen werden können.&lt;br /&gt;
&lt;br /&gt;
Nach dem Setzen der DSN sollten in der [[#Demo Library|Demo-Library]] folgende Felder gefüllt sein:&lt;br /&gt;
&lt;br /&gt;
* Host&lt;br /&gt;
* Public Key&lt;br /&gt;
* Project ID&lt;br /&gt;
&lt;br /&gt;
=== Netzwerk oder Proxy blockiert den Request ===&lt;br /&gt;
&lt;br /&gt;
Wenn die Anwendung keinen direkten Zugriff auf Sentry hat, setze einen Proxy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.iOSentry.$setProxy(&#039;proxy.example.local&#039;,&#039;8080&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Intern wird der Proxy vor dem HTTP Request gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
If not(isclear(iProxyHost))&amp;amp;not(isclear(iProxyPort))&lt;br /&gt;
	HTTPSetProxyServer (iProxyHost,iProxyPort)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Report wird lokal gespeichert ===&lt;br /&gt;
&lt;br /&gt;
Wenn &amp;lt;code&amp;gt;HTTPPost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HTTPSend&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;HTTPRead&amp;lt;/code&amp;gt; fehlschlägt, speichert OSentry den Report lokal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Calculate path as sys(115)&lt;br /&gt;
Calculate filename as con(&#039;Sentryreport_&#039;,$cinst.$getUnixTimestamp(),&#039;.json&#039;)&lt;br /&gt;
Do fOP.$createfile(con(path,filename)) Returns err&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Suche im Omnis-Installationsordner nach Dateien mit dem Namen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Sentryreport_&amp;lt;timestamp&amp;gt;.json&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sentry antwortet nicht mit 200 OK ===&lt;br /&gt;
&lt;br /&gt;
Wenn die HTTP-Antwort kein &amp;lt;code&amp;gt;200 OK&amp;lt;/code&amp;gt; enthält, wird der JSON Report ebenfalls lokal gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPRead (Socket,Buffer) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0|not(pos(&#039;200 OK&#039;,Buffer))&lt;br /&gt;
	# JSON may be corrupted or contains errors -&amp;gt; save json and the buffer as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,Buffer)&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -3&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mögliche Ursachen:&lt;br /&gt;
&lt;br /&gt;
* falsche Project ID&lt;br /&gt;
* falscher Public Key&lt;br /&gt;
* ungültige DSN&lt;br /&gt;
* JSON Payload wird von Sentry abgelehnt&lt;br /&gt;
* Netzwerk-Gateway verändert den Request&lt;br /&gt;
&lt;br /&gt;
=== Tags oder Extras erscheinen beim falschen Event ===&lt;br /&gt;
&lt;br /&gt;
[[#Tags, Extras und User-Kontext|Tags und Extras]] werden für den nächsten Request gesammelt. Nach erfolgreichem Request werden sie gelöscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iTagList.$clear()&lt;br /&gt;
Do iExtraList.$clear()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn ein Request fehlschlägt, wird ebenfalls aufgeräumt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$clearList()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prüfe trotzdem, ob in eigenen Wrapper-Methoden Tags und Extras direkt vor dem passenden Capture-Aufruf gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== User-Kontext zeigt Demo-Daten ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL.$setUser&amp;lt;/code&amp;gt; verwendet im Export feste Testdaten:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte die Methode parametrisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(pUserID,pUserName,pUserEmail)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception Demo-Button funktioniert nicht ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Trigger an SQLException&amp;lt;/code&amp;gt; ist im Export noch nicht implementiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Code need&#039;s to be written&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die produktive Methode für SQL-Fehler ist aber vorhanden. Siehe auch [[#Events erfassen|Events erfassen]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureSQLException(&#039;SQL statement failed&#039;,stat)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Zu viele Events ===&lt;br /&gt;
&lt;br /&gt;
Sentry kann sehr schnell viele Events sammeln. Verwende für produktive Systeme:&lt;br /&gt;
&lt;br /&gt;
* klare Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
* sinnvolle Levels&lt;br /&gt;
* gezielte [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* keine Events in sehr häufigen Schleifen&lt;br /&gt;
* keine rein informativen Debug-Events ohne Nutzen&lt;br /&gt;
&lt;br /&gt;
=== Sensible Daten ===&lt;br /&gt;
&lt;br /&gt;
[[#Stacktrace und Kontext|Stacktrace]], Parameter, Instance Variablen, SQL-Text und [[#Tags, Extras und User-Kontext|Extras]] können sensible Daten enthalten. Prüfe vor produktiver Nutzung:&lt;br /&gt;
&lt;br /&gt;
* Welche Variablen werden übertragen?&lt;br /&gt;
* Enthalten SQL-Statements personenbezogene Daten?&lt;br /&gt;
* Werden Tokens oder Passwörter in Extras geschrieben?&lt;br /&gt;
* Sollen bestimmte Werte maskiert werden?&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Sentry&amp;diff=9528</id>
		<title>Sentry</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Sentry&amp;diff=9528"/>
		<updated>2026-06-12T14:06:00Z</updated>

		<summary type="html">&lt;p&gt;Silvan: /* Inhalt */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- MediaWiki source for page: Sentry --&amp;gt;&lt;br /&gt;
&amp;lt;!-- Upload required files before publishing: Sentry-issue.png, Sentry-stack.png, Sentry-tags.png, Sentry-projects.png, Demo-window.svg, Demo-dsn.svg --&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Überblick ==&lt;br /&gt;
&lt;br /&gt;
OSentry ist ein REST-API-Konnektor von Omnis Studio zu Sentry. Der Konnektor sendet Fehler, Messages, Logs und Laufzeitkontext aus Omnis-Anwendungen an Sentry, damit Probleme in produktiven Systemen sichtbar, gruppierbar und analysierbar werden.&lt;br /&gt;
&lt;br /&gt;
Diese Dokumentation beschreibt die [[#Installation|Installation]], die Nutzung in bestehenden Omnis-Anwendungen, die Definition eigener standardisierter Exception-Typen, die interne Struktur und die [[#Demo Library|Demo-Library]].&lt;br /&gt;
&lt;br /&gt;
=== Kernidee ===&lt;br /&gt;
&lt;br /&gt;
OSentry besteht aus zwei produktiv relevanten Klassen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;: High-Level-Adapter für die Anwendung. Diese Klasse sollte von normalem Applikationscode aufgerufen werden.&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;: Low-Level-Adapter für DSN-Parsing, JSON-Erzeugung, [[#Stacktrace und Kontext|Stacktrace]]-Aufbereitung und HTTP-Kommunikation mit Sentry.&lt;br /&gt;
&lt;br /&gt;
Die Anwendung arbeitet im Normalfall mit &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;. Dadurch bleiben Sentry-spezifische Details zentral gekapselt und neue standardisierte Exception-Typen können als eigene Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Hauptfeatures ===&lt;br /&gt;
&lt;br /&gt;
* Direkte Anbindung von Omnis Studio an Sentry über REST API und DSN&lt;br /&gt;
* Erfassen von Exceptions, Messages, Logs und SQL-Fehlern&lt;br /&gt;
* Unterstützung der Sentry-Level &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
* Automatische Omnis-Kontextinformationen&lt;br /&gt;
* Omnis-[[#Stacktrace und Kontext|Stacktrace]] mit Klassen, Methoden, Zeilen und Variablen&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]] für Filterung und Gruppierung&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]] für zusätzliche Diagnoseinformationen&lt;br /&gt;
* Optionaler [[#Tags, Extras und User-Kontext|User-Kontext]]&lt;br /&gt;
* Proxy-Unterstützung&lt;br /&gt;
* Aktivieren und Deaktivieren der Sentry-Übertragung&lt;br /&gt;
* Lokales Speichern von Reports bei Übertragungsfehlern&lt;br /&gt;
&lt;br /&gt;
=== Weiterführende Links ===&lt;br /&gt;
&lt;br /&gt;
* [https://sentry.io/welcome/ Sentry Website]&lt;br /&gt;
* [https://sentry.io/signup/ Sentry Account erstellen]&lt;br /&gt;
* [https://develop.sentry.dev/self-hosted/ Sentry self-hosted]&lt;br /&gt;
&lt;br /&gt;
=== Screenshots ===&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-issue.png|900px|Sentry Issue-Übersicht]]&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite beschreibt, wie OSentry in eine bestehende Omnis-Anwendung integriert wird.&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* Omnis Studio Anwendung&lt;br /&gt;
* Sentry Account oder self-hosted Sentry Installation&lt;br /&gt;
* Ein Sentry-Projekt mit SDK-Typ &amp;lt;code&amp;gt;Other&amp;lt;/code&amp;gt;&lt;br /&gt;
* Die DSN des Sentry-Projekts&lt;br /&gt;
* Netzwerkzugriff auf Sentry&lt;br /&gt;
&lt;br /&gt;
Die exportierte [[#Demo Library|Demo-Library]] wurde mit Omnis &amp;lt;code&amp;gt;11.1&amp;lt;/code&amp;gt; erstellt.&lt;br /&gt;
&lt;br /&gt;
=== Sentry-Projekt erstellen ===&lt;br /&gt;
&lt;br /&gt;
# In Sentry ein neues Projekt erstellen.&lt;br /&gt;
# Als SDK &amp;lt;code&amp;gt;Other&amp;lt;/code&amp;gt; auswählen.&lt;br /&gt;
# Die DSN des Projekts kopieren.&lt;br /&gt;
&lt;br /&gt;
Die DSN wird beim Initialisieren verwendet. &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; zerlegt sie intern in Public Key, Host und Project ID.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-projects.png|900px|Sentry Projektübersicht]]&lt;br /&gt;
&lt;br /&gt;
=== Klassen kopieren ===&lt;br /&gt;
&lt;br /&gt;
Kopiere die folgenden Klassen in deine bestehende Omnis-Library:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Demo-spezifischen Klassen sind für die produktive Integration nicht erforderlich. Damit sind die übrigen Klassen der Demo-Library gemeint, zum Beispiel &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt;. Diese Klassen dienen nur dazu, die [[#Demo Library|Demo-Library]] mit Fenster, SQLite-Testdaten und Beispielaufrufen auszuführen.&lt;br /&gt;
&lt;br /&gt;
=== Task Variable anlegen ===&lt;br /&gt;
&lt;br /&gt;
Lege in deiner Startup Task eine Task Variable an:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Name !! Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; sollte als global erreichbarer Singleton der Anwendung verwendet werden. In Omnis ist dafür eine Task Variable sinnvoll, weil sie von Fenstern, Objektklassen und zentralen Error-Handlern aus konsistent erreichbar ist. Dadurch gibt es genau eine aktive Sentry-Konfiguration mit einer DSN, einem Status, optionalen Proxy-Daten und gemeinsamen Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im [[#Demo Library|Demo-Projekt]] ist diese Variable in &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; definiert.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung im Startup Task ===&lt;br /&gt;
&lt;br /&gt;
Initialisiere &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; beim Start deiner Anwendung mit der DSN deines Sentry-Projekts:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;&amp;lt;DSN&amp;gt;&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die [[#Demo Library|Demo-Library]] ruft im Startup Task ebenfalls die Initialisierung auf. Quelle: &amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init Sentry on lbs startup&lt;br /&gt;
Do tSentry.$init()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In einer produktiven Anwendung sollte die DSN explizit oder aus einer Konfiguration übergeben werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;https://PUBLIC_KEY@sentry.io/PROJECT_ID&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; Speichere die DSN in einer Datenbank, einer Konfigurationstabelle oder einem Config File. So kann sie pro Kunde, Umgebung oder Installation geändert werden, ohne die Library neu auszuliefern.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Testcall ===&lt;br /&gt;
&lt;br /&gt;
Nach der Initialisierung kann ein erstes Testevent gesendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello World!&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles korrekt eingerichtet ist, erscheint das Event im Sentry-Projekt.&lt;br /&gt;
&lt;br /&gt;
=== Proxy konfigurieren ===&lt;br /&gt;
&lt;br /&gt;
Falls die Anwendung in einem geschützten Netzwerk läuft, kann ein Proxy gesetzt werden. Die Methode befindet sich im Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.iOSentry.$setProxy(&#039;proxy.example.local&#039;,&#039;8080&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die interne Implementierung setzt den Proxy vor dem HTTP-Request:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Configure proxy; needed when sending data out of secured networks&lt;br /&gt;
If not(isclear(iProxyHost))&amp;amp;not(isclear(iProxyPort))&lt;br /&gt;
	HTTPSetProxyServer (iProxyHost,iProxyPort)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sentry aktivieren oder deaktivieren ===&lt;br /&gt;
&lt;br /&gt;
OSentry kann zentral ein- oder ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; Deaktiviere Sentry in der Entwicklungs-Version standardmäßig oder verwende eine separate Entwicklungs-DSN. So landen lokale Tests, Debug-Fehler und absichtlich ausgelöste Exceptions nicht im produktiven Sentry-Projekt.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$setStatus(1)     ## aktiv&lt;br /&gt;
Do tSentry.$setStatus(0)     ## inaktiv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; wird vor dem Senden geprüft:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Check if Sentry is enabled&lt;br /&gt;
If iStatus=0|isclear(iStatus)&lt;br /&gt;
	Quit method 0&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite zeigt die minimale Integration in eine bestehende Omnis-Anwendung.&lt;br /&gt;
&lt;br /&gt;
=== Klassen übernehmen ===&lt;br /&gt;
&lt;br /&gt;
Kopiere &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; in deine Library.&lt;br /&gt;
&lt;br /&gt;
=== Task Variable erstellen ===&lt;br /&gt;
&lt;br /&gt;
In der Startup Task:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Name !! Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sentry initialisieren ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;https://PUBLIC_KEY@sentry.io/PROJECT_ID&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL.$init&amp;lt;/code&amp;gt; delegiert an das Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init of the main sentry object&lt;br /&gt;
Do iOSentry.$init(pDSN)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message senden ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die [[#Demo Library|Demo-Library]] verwendet genau diesen Aufruf im Button &amp;lt;code&amp;gt;Trigger a message&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.message.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exception senden ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== In Sentry prüfen ===&lt;br /&gt;
&lt;br /&gt;
In Sentry sollte anschließend ein neues Event sichtbar sein. Je nach Event-Typ enthält es:&lt;br /&gt;
&lt;br /&gt;
* Message&lt;br /&gt;
* Level&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|User-Kontext]]&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]]&lt;br /&gt;
* Omnis-Kontextinformationen&lt;br /&gt;
&lt;br /&gt;
== Events erfassen ==&lt;br /&gt;
&lt;br /&gt;
OSentryHL ist die empfohlene Einstiegsschicht für Applikationscode. Die Klasse bietet sprechende Methoden für typische Event-Arten und ruft intern &amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
&lt;br /&gt;
=== Message ===&lt;br /&gt;
&lt;br /&gt;
Eine einfache Information wird mit &amp;lt;code&amp;gt;$captureMessage&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello World!&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an Info Message&lt;br /&gt;
Do iOSentry.$captureException(pMessage,3,,&#039;info&#039;,kFalse,,kFalse) Returns code&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Level: &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;&lt;br /&gt;
* Kein [[#Stacktrace und Kontext|Stacktrace]]&lt;br /&gt;
* Kein [[#Tags, Extras und User-Kontext|User Interface]]&lt;br /&gt;
* Geeignet für einfache Statusmeldungen oder technische Hinweise&lt;br /&gt;
&lt;br /&gt;
=== Log ===&lt;br /&gt;
&lt;br /&gt;
Ein Log-Event wird mit &amp;lt;code&amp;gt;$captureLog&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureLog(&#039;Uh oh this is a Log because something went wrong&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a Log Sentry Report&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;Log&#039;,&#039;warning&#039;,1,0,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Level: &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]] aktiv&lt;br /&gt;
* Exception Interface in diesem Wrapper deaktiviert&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|User Interface]] aktiv&lt;br /&gt;
&lt;br /&gt;
=== Generische Exception ===&lt;br /&gt;
&lt;br /&gt;
Eine generische Exception wird mit &amp;lt;code&amp;gt;$captureException&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture a generic Exception&lt;br /&gt;
#Add any custom tags / extras&lt;br /&gt;
Do $cinst.$addTag(&#039;Custom Test Tag&#039;,&#039;Euromnis&#039;)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; || Text, der in Sentry als Message sichtbar ist&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; || Fehlercode oder fachlicher Code&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExcType&amp;lt;/code&amp;gt; || Exception-Typ für Benennung und Gruppierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pLevel&amp;lt;/code&amp;gt; || Sentry-Level&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Gültige Levels:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception ===&lt;br /&gt;
&lt;br /&gt;
SQL-Fehler können mit &amp;lt;code&amp;gt;$captureSQLException&amp;lt;/code&amp;gt; gemeldet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureSQLException(&#039;SQL statement failed&#039;,stat)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Fügt die Datenbank als [[#Tags, Extras und User-Kontext|Tag]] hinzu&lt;br /&gt;
* Fügt SQL-Text als [[#Tags, Extras und User-Kontext|Extra]] hinzu&lt;br /&gt;
* Fügt native Datenbankfehlermeldung als [[#Tags, Extras und User-Kontext|Extra]] hinzu&lt;br /&gt;
* Sendet das Event als &amp;lt;code&amp;gt;SQL-Exception&amp;lt;/code&amp;gt; mit Level &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deprecated Call ===&lt;br /&gt;
&lt;br /&gt;
Veraltete Codepfade können gezielt gemeldet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureDeprecatedCall()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Wrapper eignet sich, um zu erkennen, ob alter Code in produktiven Systemen noch ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
=== Frei konfigurierbares Event ===&lt;br /&gt;
&lt;br /&gt;
Für Sonderfälle gibt es &amp;lt;code&amp;gt;$captureAnything&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureAnything(&#039;Text&#039;,1001,&#039;Custom Type&#039;,&#039;error&#039;,kTrue,kTrue,kTrue)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Capture a generic Sentry Report (max configurability)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Methode bietet maximale Flexibilität. Für wiederkehrende Exception-Typen sollte aber eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; angelegt werden. Siehe [[#Eigene Exceptions standardisieren|04 Eigene Exceptions standardisieren]].&lt;br /&gt;
&lt;br /&gt;
== Eigene Exceptions standardisieren ==&lt;br /&gt;
&lt;br /&gt;
Wenn ein Exception-Typ mehrfach in der Anwendung vorkommt, sollte er nicht überall manuell mit &amp;lt;code&amp;gt;$captureException&amp;lt;/code&amp;gt; aufgebaut werden. Besser ist eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dadurch entsteht eine zentrale, wiederverwendbare Definition für:&lt;br /&gt;
&lt;br /&gt;
* Exception-Typ&lt;br /&gt;
* Sentry-Level&lt;br /&gt;
* Fehlercode&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]]&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]]/[[#Tags, Extras und User-Kontext|User]]/Exception Interface&lt;br /&gt;
&lt;br /&gt;
Die automatisch gesetzten [[#Tags, Extras und User-Kontext|Tags und Extras]] aus &amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; müssen in solchen Wrappern nicht erneut ergänzt werden. Eigene Exception-Methoden setzen nur zusätzliche Werte, die für diesen standardisierten Exception-Typ relevant sind.&lt;br /&gt;
&lt;br /&gt;
=== Warum über OSentryHL? ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ist die Abstraktionsschicht für Applikationscode. Sie kapselt die Details von &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und sorgt dafür, dass Aufrufe in der Anwendung kurz und konsistent bleiben.&lt;br /&gt;
&lt;br /&gt;
Bestehende Beispiele aus &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Empfohlenes Muster ===&lt;br /&gt;
&lt;br /&gt;
Für jeden standardisierten Exception-Typ wird eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; erstellt.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a validation exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Field&#039;,pField)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Invalid Value&#039;,pValue)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,2001,&#039;Validation-Exception&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mögliche Parameter der neuen Methode:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Beispiel !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;Invalid customer number&#039;&amp;lt;/code&amp;gt; || Sentry Message&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pModule&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;Customer&#039;&amp;lt;/code&amp;gt; || Filterbarer Tag&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pField&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;cu_number&#039;&amp;lt;/code&amp;gt; || Diagnoseinformation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pValue&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;ABC&#039;&amp;lt;/code&amp;gt; || Diagnoseinformation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der Applikationscode bleibt dadurch einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureValidationException(&#039;Invalid customer number&#039;,&#039;Customer&#039;,&#039;cu_number&#039;,cu_number)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel: Business Rule Exception ===&lt;br /&gt;
&lt;br /&gt;
Neue Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a business rule violation&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addTag(&#039;Business Rule&#039;,pRuleName)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Details&#039;,pDetails)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aufruf in der Anwendung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureBusinessRuleViolation(&#039;Invoice cannot be posted&#039;,&#039;Invoice&#039;,&#039;PostingAllowed&#039;,&#039;Invoice is missing customer&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel: Integration Exception ===&lt;br /&gt;
&lt;br /&gt;
Neue Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an integration exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Integration&#039;,pSystem)&lt;br /&gt;
Do $cinst.$addTag(&#039;Endpoint&#039;,pEndpoint)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Payload&#039;,pPayload)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Response&#039;,pResponse)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,4001,&#039;Integration-Exception&#039;,&#039;error&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aufruf in der Anwendung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureIntegrationException(&#039;External API request failed&#039;,&#039;ERP&#039;,&#039;/api/customer&#039;,jsonPayload,responseText)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Namenskonventionen ===&lt;br /&gt;
&lt;br /&gt;
Empfehlung für neue Methoden:&lt;br /&gt;
&lt;br /&gt;
* Methodenname beginnt mit &amp;lt;code&amp;gt;$capture&amp;lt;/code&amp;gt;&lt;br /&gt;
* Der fachliche Typ steht im Methodennamen&lt;br /&gt;
* Der Sentry Exception Type ist stabil und ändert sich nicht laufend&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]] sind kurz und filterbar&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]] dürfen länger sein und Diagnoseinformationen enthalten&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureValidationException&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureBusinessRuleViolation&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureIntegrationException&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$capturePermissionViolation&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureConfigurationError&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error Codes ===&lt;br /&gt;
&lt;br /&gt;
Verwende feste Fehlercodes für standardisierte Exception-Typen. Dadurch können Events in Sentry besser gefiltert und wiedererkannt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Code !! Exception Type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Validation-Exception&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Business-Rule-Violation&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Integration-Exception&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;5001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Configuration-Error&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wann nicht standardisieren? ===&lt;br /&gt;
&lt;br /&gt;
Nicht jeder Einzelfall braucht eine eigene Methode. Für einmalige technische Tests oder sehr spezielle Fälle reicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald ein Exception-Typ aber mehrfach vorkommt oder fachlich relevant ist, sollte er als eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
== Tags, Extras und User-Kontext ==&lt;br /&gt;
&lt;br /&gt;
Tags, Extras und User-Kontext reichern Sentry-Events mit zusätzlichen Informationen an. Diese Informationen helfen beim Filtern, Gruppieren und Analysieren.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-tags.png|900px|Sentry Tags und User-Kontext]]&lt;br /&gt;
&lt;br /&gt;
=== Tags ===&lt;br /&gt;
&lt;br /&gt;
Tags sind kurze, filterbare Werte.&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* Datenbank&lt;br /&gt;
* Kunde&lt;br /&gt;
* Modul&lt;br /&gt;
* Umgebung&lt;br /&gt;
* Error Code&lt;br /&gt;
* Omnis-Version&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add a Tag to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addTag(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Adds a tag to the next request processed&lt;br /&gt;
Do iTagList.$add(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$addTag(&#039;Module&#039;,&#039;Invoice&#039;)&lt;br /&gt;
Do tSentry.$addTag(&#039;Customer&#039;,&#039;10001&#039;)&lt;br /&gt;
Do tSentry.$captureException(&#039;Invoice posting failed&#039;,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Extras ===&lt;br /&gt;
&lt;br /&gt;
Extras sind Detailinformationen, die nicht primär zum Filtern gedacht sind.&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* SQL-Text&lt;br /&gt;
* Native Datenbankfehlermeldung&lt;br /&gt;
* Payload&lt;br /&gt;
* Response Body&lt;br /&gt;
* interne IDs&lt;br /&gt;
* zusätzliche Debug-Informationen&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add an Extra to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addExtra(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Adds extra information to the next request being processed&lt;br /&gt;
Do iExtraList.$add(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel aus der SQL Exception:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Automatische Tags ===&lt;br /&gt;
&lt;br /&gt;
Die folgenden Tags werden bei jedem Event automatisch von &amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; ergänzt. Sie müssen bei eigenen Exceptions nicht erneut gesetzt werden. Eigene Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; sollten nur zusätzliche, fachlich oder technisch relevante Tags hinzufügen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; fügt mehrere Tags automatisch hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add static tags&lt;br /&gt;
Do iTagList.$add(&#039;Omnisversion&#039;,sys(1))&lt;br /&gt;
Calculate systemversionRow as systemversion()&lt;br /&gt;
Do iTagList.$add(&#039;Plattform&#039;,con(sys(8),pick(systemversionRow.server,&#039;&#039;,&#039; SRV&#039;)))&lt;br /&gt;
Do iTagList.$add(&#039;OS Version&#039;,con(systemversionRow.major,&#039;.&#039;,systemversionRow.minor,&#039;.&#039;,systemversionRow.build))&lt;br /&gt;
Do iTagList.$add(&#039;error_code&#039;,pErrorCode)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Automatisch gesendete Tags:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tag !! Herkunft !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Omnisversion&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;sys(1)&amp;lt;/code&amp;gt; || Zeigt, mit welcher Omnis-Version das Event erzeugt wurde&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Plattform&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;sys(8)&amp;lt;/code&amp;gt; und Server-Flag aus &amp;lt;code&amp;gt;systemversion()&amp;lt;/code&amp;gt; || Unterscheidet Plattform und Server Runtime&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OS Version&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;systemversionRow.major/minor/build&amp;lt;/code&amp;gt; || Zeigt die Betriebssystemversion&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;error_code&amp;lt;/code&amp;gt; || Parameter &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; || Verbindet das Event mit dem übergebenen Fehlercode&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Beispiel für eine eigene Exception: Der Wrapper muss nicht erneut &amp;lt;code&amp;gt;Omnisversion&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;OS Version&amp;lt;/code&amp;gt; setzen. Er ergänzt nur das, was für diesen Exception-Typ zusätzlich hilfreich ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addTag(&#039;Business Rule&#039;,pRuleName)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Automatische Extras ===&lt;br /&gt;
&lt;br /&gt;
Auch die folgenden Extras werden bei jedem Event automatisch ergänzt. Bei eigenen Exceptions müssen nur zusätzliche Extras gesetzt werden, zum Beispiel ein SQL-Statement, ein Payload oder fachliche Zusatzdaten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; fügt offene Fenster, offene Reports und die aktuelle Printfile hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Static extra 1: All open windows&lt;br /&gt;
Do $root.$iwindows.$makelist($ref.$name) Returns nameList&lt;br /&gt;
For i from 1 to nameList.$linecount step 1&lt;br /&gt;
	Calculate windows as con(windows,&#039;, &#039;,nameList.[i].1)&lt;br /&gt;
End For&lt;br /&gt;
Calculate windows as right(windows,len(windows)-2)&lt;br /&gt;
Do iExtraList.$add(&#039;Open Windows&#039;,windows)&lt;br /&gt;
&lt;br /&gt;
# Static extra 2: All open reports&lt;br /&gt;
Do $root.$ireports.$makelist($ref.$name) Returns nameList&lt;br /&gt;
For i from 1 to nameList.$linecount step 1&lt;br /&gt;
	Calculate reports as con(reports,&#039;, &#039;,nameList.[i].1)&lt;br /&gt;
End For&lt;br /&gt;
Calculate reports as right(reports,len(reports)-2)&lt;br /&gt;
Do iExtraList.$add(&#039;Open Reports&#039;,reports)&lt;br /&gt;
Do iExtraList.$add(&#039;Current Printfile&#039;,$root.$prefs.$printfile)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Automatisch gesendete Extras:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Extra !! Herkunft !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Open Windows&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$iwindows.$makelist($ref.$name)&amp;lt;/code&amp;gt; || Zeigt, welche Fenster im Moment des Events offen waren&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Open Reports&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$ireports.$makelist($ref.$name)&amp;lt;/code&amp;gt; || Zeigt, welche Reports im Moment des Events offen waren&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Current Printfile&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$prefs.$printfile&amp;lt;/code&amp;gt; || Zeigt die aktuell gesetzte Printfile&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Beispiel für zusätzliche Extras in einem eigenen Wrapper:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addExtra(&#039;Payload&#039;,pPayload)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Response&#039;,pResponse)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,4001,&#039;Integration-Exception&#039;,&#039;error&#039;,1,1,1) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== User-Kontext ===&lt;br /&gt;
&lt;br /&gt;
Der User-Kontext ordnet ein Event einem betroffenen Benutzer zu. In Sentry erscheint dadurch ein eigener User-Bereich, und Events können nach Benutzer gefiltert oder gruppiert werden. Das ist besonders hilfreich, wenn ein Fehler nur bei einzelnen Kunden, Arbeitsplätzen oder Benutzerkonten auftritt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; unterstützt drei User-Felder:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feld !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt; || stabile interne Benutzer-ID oder Kundennummer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;username&amp;lt;/code&amp;gt; || lesbarer Benutzername&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;email&amp;lt;/code&amp;gt; || E-Mail-Adresse, falls sie übertragen werden darf&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der User-Kontext wird nur in das Event geschrieben, wenn das User Interface beim Capture-Aufruf aktiviert ist. Die Standardmethode &amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; hat &amp;lt;code&amp;gt;pUserInterface&amp;lt;/code&amp;gt; standardmäßig auf &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt;. Einzelne High-Level-Methoden können das bewusst deaktivieren, zum Beispiel &amp;lt;code&amp;gt;$captureMessage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; kann User-Daten an das Event anhängen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Sets userinformation for the next request being processed&lt;br /&gt;
Calculate iUserID as pID&lt;br /&gt;
Calculate iUserName as pName&lt;br /&gt;
Calculate iUserEmail as pEmail&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das User Interface wird so generiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Create user data row&lt;br /&gt;
Do UserdataRow.$define(id,email,username)&lt;br /&gt;
&lt;br /&gt;
Calculate UserdataRow.id as iUserID&lt;br /&gt;
Calculate UserdataRow.email as iUserEmail&lt;br /&gt;
Calculate UserdataRow.username as iUserName&lt;br /&gt;
&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;user&#039;,&#039;&#039;)&lt;br /&gt;
Do JSON.$setobject(&#039;user&#039;,UserdataRow)&lt;br /&gt;
&lt;br /&gt;
Calculate jsonString as OJSON.$formatjson(JSON.$getjson())&lt;br /&gt;
&lt;br /&gt;
Quit method jsonString&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die aktuelle Demo-Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; verwendet feste Testdaten. Quelle: &amp;lt;code&amp;gt;OSentryHL.$setUser&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Set the User which should be linked to the Sentry Issue&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte diese Methode angepasst und parametrisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(pUserID,pUserName,pUserEmail)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Empfohlen ist, den User nach Login oder beim Wechsel des aktiven Benutzers zentral zu setzen. Bei anonymen oder sensiblen Installationen kann statt Name und E-Mail auch nur eine interne ID oder ein pseudonymisierter Wert verwendet werden.&lt;br /&gt;
&lt;br /&gt;
=== Datenschutz ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #72777d; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Datenschutz:&#039;&#039;&#039; Prüfe vor produktiver Nutzung, welche Daten an Sentry gesendet werden. Besonders kritisch sind personenbezogene Daten, SQL-Statements, Zugangsdaten, Tokens und interne Pfade.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Besonders kritisch sind:&lt;br /&gt;
&lt;br /&gt;
* personenbezogene Daten&lt;br /&gt;
* Kundendaten&lt;br /&gt;
* SQL-Statements mit Werten&lt;br /&gt;
* Zugangsdaten&lt;br /&gt;
* Tokens&lt;br /&gt;
* interne Pfade&lt;br /&gt;
&lt;br /&gt;
Tags und Extras sollten so gestaltet werden, dass sie für die Fehleranalyse hilfreich sind, aber keine unnötigen sensiblen Daten übertragen.&lt;br /&gt;
&lt;br /&gt;
== Stacktrace und Kontext ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; erzeugt einen Omnis-spezifischen Stacktrace und übergibt ihn an Sentry. Dadurch sieht man in Sentry nicht nur eine Fehlermeldung, sondern auch Klassen, Methoden, Zeilen und Variablenkontext. Ergänzende Informationen zu [[#Tags, Extras und User-Kontext|Tags, Extras und User-Kontext]] stehen auf der separaten Kontext-Seite.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-stack.png|900px|Sentry Stacktrace mit Omnis-Kontext]]&lt;br /&gt;
&lt;br /&gt;
=== Stack lesen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateStacktraceInterface&amp;lt;/code&amp;gt; verwendet &amp;lt;code&amp;gt;sys(192)&amp;lt;/code&amp;gt;, um den aktuellen Omnis-Stack zu lesen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Clean up the Stacklist (remove OSentry classes from the stack)&lt;br /&gt;
Do sys(192) Returns sys192List&lt;br /&gt;
For sys192List.$line from 1 to sys192List.$linecount step 1&lt;br /&gt;
	Set reference class to sys192List.classitem&lt;br /&gt;
	If pos(&#039;OSentry&#039;,class.$name)&amp;gt;0|pos(&#039;OSentryHL&#039;,class.$name)&amp;gt;0&lt;br /&gt;
		Do sys192List.[sys192List.$line].$selected.$assign(kTrue)&lt;br /&gt;
	End If&lt;br /&gt;
End For&lt;br /&gt;
Do sys192List.$remove(kListDeleteSelected)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Interne Frames von &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; werden entfernt, damit in Sentry die fachlich relevanten Stellen sichtbar bleiben.&lt;br /&gt;
&lt;br /&gt;
=== SQL-Error Frames entfernen ===&lt;br /&gt;
&lt;br /&gt;
Bestimmte interne SQL-Fehlerframes werden ebenfalls entfernt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Remove some other classes which we do not want to display&lt;br /&gt;
If sys192List.1.method=&#039;$sqlerror&#039;&lt;br /&gt;
	Do sys192List.$remove(1)&lt;br /&gt;
Else If sys192List.1.method=&#039;$statementerror&#039;&lt;br /&gt;
	Do sys192List.$remove(1)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frames erzeugen ===&lt;br /&gt;
&lt;br /&gt;
Für jeden Stack-Eintrag werden Funktion, Zeilennummer und Kontextzeile erzeugt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Loop through every item on the omnis stack&lt;br /&gt;
For sys192List.$line from 1 to sys192List.$linecount step 1&lt;br /&gt;
	Set reference class to sys192List.classitem&lt;br /&gt;
	Calculate className as class.$name&lt;br /&gt;
	&lt;br /&gt;
	# Create the content row&lt;br /&gt;
	Do contentRow.$define(vars,function,pre_context,context_line,lineno,filename,post_context)&lt;br /&gt;
	Calculate contentRow.lineno as sys192List.line&lt;br /&gt;
	Calculate contentRow.filename as testFileName&lt;br /&gt;
	Calculate contentRow.context_line as sys192List.linetext&lt;br /&gt;
	If isclear(sys192List.object)&lt;br /&gt;
		Calculate contentRow.function as con(className,&#039;.&#039;,sys192List.method) ## If it&#039;s a class method&lt;br /&gt;
	Else&lt;br /&gt;
		Calculate contentRow.function as con(className,&#039;.&#039;,sys192List.object,&#039;.&#039;,sys192List.method) ## If it&#039;s a method of an object of a class (e.g. Headedlist)&lt;br /&gt;
	End If&lt;br /&gt;
	Do contentList.$add(contentRow)&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablen aufnehmen ===&lt;br /&gt;
&lt;br /&gt;
Pro Stackframe werden Instance Variablen und Parameter gesammelt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Get all iVars&lt;br /&gt;
Do varList.$define(name,value)&lt;br /&gt;
Set reference class to sys192List.inst&lt;br /&gt;
Do $cinst.$getVars(&#039;ivars&#039;,class) Returns varList&lt;br /&gt;
&lt;br /&gt;
# Get all params&lt;br /&gt;
Calculate paramList as sys192List.params&lt;br /&gt;
For paramList.$line from 1 to paramList.$linecount step 1&lt;br /&gt;
	If not(paramList.value=&#039;(Not empty)&#039;)&lt;br /&gt;
		Do varList.$add(paramList.name,paramList.value)&lt;br /&gt;
	Else&lt;br /&gt;
		Do varList.$add(paramList.name,&#039;(Not empty)&#039;)&lt;br /&gt;
	End If&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pre- und Post-Context ===&lt;br /&gt;
&lt;br /&gt;
OSentry fügt Methodenzeilen vor und nach der aktuellen Zeile hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Pre Context (all method lines before the error occured)&lt;br /&gt;
Set reference method to sys192List.methoditem&lt;br /&gt;
Do precontextList.$define(line)&lt;br /&gt;
For i from 1 to sys192List.line-1 step 1&lt;br /&gt;
	Do precontextList.$add(method.$methodlines.[i].$text)&lt;br /&gt;
End For&lt;br /&gt;
&lt;br /&gt;
# Post Context (all method lines after the error occured&lt;br /&gt;
Do postcontextList.$define(line)&lt;br /&gt;
For i from sys192List.line+1 to method.$methodlines.$count step 1&lt;br /&gt;
	Do postcontextList.$add(method.$methodlines.[i].$text)&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablentypen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$getVars&amp;lt;/code&amp;gt; unterstützt Basisvariablen, Rows und Lists.&lt;br /&gt;
&lt;br /&gt;
Basisvariablen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
If varType=&#039;char&#039;|varType=&#039;boolean&#039;|varType=&#039;integer&#039;|varType=&#039;number&#039;|varType=&#039;date&#039;&lt;br /&gt;
	Calculate varContent as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	Do varList.$add(varName,varContent)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Else If varType=&#039;row&#039;&lt;br /&gt;
	Calculate varRow as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	If varRow.$colcount=0&lt;br /&gt;
		Do varList.$add(varName,&#039;(Empty)&#039;)&lt;br /&gt;
	Else&lt;br /&gt;
		For Z2 from 1 to varRow.$colcount step 1&lt;br /&gt;
			Calculate varContent as con(varContent,varRow.$cols.[Z2].$name,&#039;: &#039;,varRow.[Z2],&#039;, &#039;)&lt;br /&gt;
		End For&lt;br /&gt;
		Do varList.$add(varName,varContent)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lists:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Else If varType=&#039;list&#039;&lt;br /&gt;
	Calculate varListType as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	Calculate varContent as con(&#039;Colcount: &#039;,varListType.$colcount,&#039;, &#039;,&#039;Linecount: &#039;,varListType.$linecount,&#039;, &#039;,&#039;Current Line: &#039;,varListType.$line)&lt;br /&gt;
	If varListType.$linecount=0&amp;amp;varListType.$line=0&amp;amp;varListType.$colcount=0&lt;br /&gt;
		Do varList.$add(varName,&#039;(Empty)&#039;)&lt;br /&gt;
		Calculate varContent as &#039;&#039;&lt;br /&gt;
	Else&lt;br /&gt;
		For Z3 from 1 to varListType.$colcount step 1&lt;br /&gt;
			Calculate colName as varListType.$cols.[Z3].$name&lt;br /&gt;
			Calculate varContent as con(varContent,&#039;  &#039;,colName,&#039;: &#039;,varListType.[colName])&lt;br /&gt;
		End For&lt;br /&gt;
		Do varList.$add(varName,varContent)&lt;br /&gt;
		Calculate varContent as &#039;&#039;&lt;br /&gt;
	End If&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
&lt;br /&gt;
Stacktrace und Variablenkontext sind sehr hilfreich, können aber sensible Daten enthalten. Vor produktiver Nutzung sollte geprüft werden, ob bestimmte Variablen anonymisiert oder ausgeschlossen werden müssen.&lt;br /&gt;
&lt;br /&gt;
== Interne Architektur ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite beschreibt die produktiv relevanten Klassen &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Klassenübersicht ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Rolle&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; || High-Level-Adapter für Applikationscode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; || Low-Level-Adapter für JSON, [[#Stacktrace und Kontext|Stacktrace]] und HTTP&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Startup und Beispiel für Initialisierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Code für [[#Stacktrace und Kontext|Stacktrace]]-Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-DB Initialisierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt; || SQLite Session für [[#Demo Library|Demo]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Empfohlener Aufrufweg ===&lt;br /&gt;
&lt;br /&gt;
Applikationscode sollte &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; verwenden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; delegiert anschließend an &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ablauf eines Events ===&lt;br /&gt;
&lt;br /&gt;
# Applikationscode ruft Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; fügt bei Bedarf [[#Tags, Extras und User-Kontext|Tags und Extras]] hinzu.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ruft &amp;lt;code&amp;gt;iOSentry.$captureException(...)&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; prüft, ob Sentry aktiv ist.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; erzeugt JSON.&lt;br /&gt;
# [[#Stacktrace und Kontext|Stacktrace]], Exception Interface und [[#Tags, Extras und User-Kontext|User Interface]] werden optional ergänzt.&lt;br /&gt;
# HTTP Header und Sentry Auth Header werden erstellt.&lt;br /&gt;
# JSON wird per HTTPS an Sentry gesendet.&lt;br /&gt;
# Bei Erfolg werden [[#Tags, Extras und User-Kontext|Tags und Extras]] geleert.&lt;br /&gt;
# Bei Fehler wird der JSON Report lokal gespeichert.&lt;br /&gt;
&lt;br /&gt;
=== DSN Parsing ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$init&amp;lt;/code&amp;gt; zerlegt die DSN:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Parse the DSN into Public Key, Host and Project ID&lt;br /&gt;
If len(pDSN)&amp;gt;5&lt;br /&gt;
	Calculate iDSN as pDSN&lt;br /&gt;
	Calculate part1 as strtok(&#039;iDSN&#039;,&#039;@&#039;)&lt;br /&gt;
	Calculate iProtocol as strtok(&#039;part1&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iProtocol as left(iProtocol,len(iProtocol)-1)&lt;br /&gt;
	Do strtok(&#039;part1&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iPubKey as strtok(&#039;part1&#039;,&#039;:&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Calculate iHost as strtok(&#039;iDSN&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iProID as iDSN&lt;br /&gt;
	&lt;br /&gt;
	#Save the values for the next startup&lt;br /&gt;
	Calculate $cclass.$ivardefs.iPubKey.$objinitval as con(&#039;&amp;quot;&#039;,iPubKey,&#039;&amp;quot;&#039;)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iHost.$objinitval as con(&#039;&amp;quot;&#039;,iHost,&#039;&amp;quot;&#039;)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iProID.$objinitval as con(&#039;&amp;quot;&#039;,iProID,&#039;&amp;quot;&#039;)&lt;br /&gt;
End If&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== JSON-Erzeugung ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; ist die zentrale Methode für den Payload. Sie setzt unter anderem:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;event_id&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;logger&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;platform&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;culprit&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;timestamp&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sdk&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;message&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;level&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;tags&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;extra&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;exception&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;stacktrace&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auszug:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add all required fields (those are required from the API)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;event_id&#039;,$cinst.$generateUUID()) ## auto generated UUID 4&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;logger&#039;,logger)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;platform&#039;,platform)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;culprit&#039;,culprit)&lt;br /&gt;
#Do JSON.$addmember(&#039;&#039;,&#039;release&#039;,release)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;timestamp&#039;,timestamp)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;sdk&#039;,&#039;&#039;)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;message&#039;,pErrorText)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;level&#039;,pLevel)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;tags&#039;,&#039;&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== HTTP-Kommunikation ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; sendet den erzeugten JSON-Payload an Sentry:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Generate HTTP Auth header&lt;br /&gt;
Begin text block&lt;br /&gt;
Text:Sentry sentry_version=7,&lt;br /&gt;
Text:sentry_timestamp=[$cinst.$getUnixTimestamp()],&lt;br /&gt;
Text:sentry_key=[iPubKey],&lt;br /&gt;
Text:sentry_client=omnis/1.0&lt;br /&gt;
End text block&lt;br /&gt;
Get text block auth&lt;br /&gt;
&lt;br /&gt;
#Generate header list&lt;br /&gt;
Calculate Host as &#039;sentry.io&#039;&lt;br /&gt;
Calculate Url as con(&#039;/api/&#039;,iProID,&#039;/store/&#039;)&lt;br /&gt;
Do HdrList.$define(wert,name)&lt;br /&gt;
Do HdrList.$add(&#039;User-Agent&#039;,&#039;omnis/1.0&#039;)&lt;br /&gt;
Do HdrList.$add(&#039;Content-Type&#039;,&#039;application/json&#039;)&lt;br /&gt;
Do HdrList.$add(&#039;Content-Length&#039;,binlength(json))&lt;br /&gt;
Do HdrList.$add(&#039;X-Sentry-Auth&#039;,auth)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anschließend wird der Request über &amp;lt;code&amp;gt;HTTPPost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HTTPSend&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;HTTPRead&amp;lt;/code&amp;gt; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
=== Fehlerbehandlung beim Senden ===&lt;br /&gt;
&lt;br /&gt;
Wenn der Socket nicht geöffnet werden kann:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPPost (Host,Url,,HdrList,443,kTrue,kTrue) Returns Socket&lt;br /&gt;
If Socket&amp;lt;0&lt;br /&gt;
	#Error when opening connection -&amp;gt; save json as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,con(&#039;Error &#039;,Socket,&#039; when performing HTTPPost&#039;))&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -1&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn das Senden fehlschlägt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPSend (Socket,json) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0&lt;br /&gt;
	# Error while sending data -&amp;gt; save json as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,con(&#039;Erorr &#039;,byteCount,&#039; when performing HTTPSend&#039;))&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -2&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn die Antwort nicht erfolgreich ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPRead (Socket,Buffer) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0|not(pos(&#039;200 OK&#039;,Buffer))&lt;br /&gt;
	# JSON may be corrupted or contains errors -&amp;gt; save json and the buffer as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,Buffer)&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -3&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Lokales Speichern ===&lt;br /&gt;
&lt;br /&gt;
Bei Fehlern wird der JSON Report lokal im Omnis-Installationsordner gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Writes the json and the http buffer to a file in the omnis installation folder&lt;br /&gt;
Calculate path as sys(115)&lt;br /&gt;
Calculate filename as con(&#039;Sentryreport_&#039;,$cinst.$getUnixTimestamp(),&#039;.json&#039;)&lt;br /&gt;
Do fOP.$createfile(con(path,filename)) Returns err&lt;br /&gt;
Do fOP.$writecharacter(kUniTypeUTF8,pJSON) Returns err&lt;br /&gt;
If not(isclear(pBuffer))&lt;br /&gt;
	Do fOP.$writecharacter(kUniTypeUTF8,con(kCr,pBuffer),kTrue) Returns err&lt;br /&gt;
End If&lt;br /&gt;
Do fOP.$closefile()&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cleanup ===&lt;br /&gt;
&lt;br /&gt;
Nach erfolgreichem Senden werden [[#Tags, Extras und User-Kontext|Tags und Extras]] gelöscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Clears all extras and tags =&amp;gt; to be used after a sentry request has successfully been sent&lt;br /&gt;
Do iTagList.$clear()&lt;br /&gt;
Do iExtraList.$clear()&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Demo Library ==&lt;br /&gt;
&lt;br /&gt;
Die Demo-Library zeigt, wie &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; initialisiert wird und wie verschiedene [[#Events erfassen|Event-Typen]] aus einer Omnis-Oberfläche heraus an Sentry gesendet werden.&lt;br /&gt;
&lt;br /&gt;
=== Bestandteile ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; || Initialisiert Sentry, SQLite und öffnet das Demo-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; || Demo-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt; || Erzeugt Demo-Stack für Exception&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; || Erstellt SQLite-Demo-Datenbank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt; || SQLite Session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; || Low-Level-Sentry-Adapter&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; || High-Level-Sentry-Adapter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt; initialisiert Sentry, baut eine SQLite Session auf und öffnet das Demo-Fenster. Quelle: &amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init Sentry on lbs startup&lt;br /&gt;
Do tSentry.$init()&lt;br /&gt;
&lt;br /&gt;
#SQLite Session init&lt;br /&gt;
Do $objects.OSLSession.$newref() Returns tOSLSession&lt;br /&gt;
#Calculate tOSLSession.$opencreate as kTrue&lt;br /&gt;
Calculate workingDir as tODatabaseHandler.$getWorkingDir()&lt;br /&gt;
Do con(workingDir,&#039;Sentry_Test.db&#039;) Returns dbLocation&lt;br /&gt;
Do tOSLSession.$logon(dbLocation,&#039;&#039;,&#039;&#039;,&#039;slsession&#039;) Returns #F&lt;br /&gt;
&lt;br /&gt;
#Open Test Window&lt;br /&gt;
Do $windows.FSY_Demo.$openonce(&#039;*&#039;)&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Demo-Fenster ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; enthält folgende Bereiche:&lt;br /&gt;
&lt;br /&gt;
* DSN Configuration&lt;br /&gt;
* DB Status&lt;br /&gt;
* Actions&lt;br /&gt;
&lt;br /&gt;
Wichtige Felder:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feld !! Datenanbindung&lt;br /&gt;
|-&lt;br /&gt;
| DSN || &amp;lt;code&amp;gt;iDSN&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Host || &amp;lt;code&amp;gt;tSentry.iOSentry.iHost&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Public Key || &amp;lt;code&amp;gt;tSentry.iOSentry.iPubKey&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Project ID || &amp;lt;code&amp;gt;tSentry.iOSentry.iProID&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| DB Status || &amp;lt;code&amp;gt;iCurrentDBStatus&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Datei:Demo-window.svg|850px|Demo-Fenster der OSentry Library]]&lt;br /&gt;
&lt;br /&gt;
=== DSN setzen ===&lt;br /&gt;
&lt;br /&gt;
Die DSN wird im Feld &amp;lt;code&amp;gt;iDSN&amp;lt;/code&amp;gt; erfasst. Der Button &amp;lt;code&amp;gt;Set DSN&amp;lt;/code&amp;gt; ruft anschließend &amp;lt;code&amp;gt;tSentry.$init(iDSN)&amp;lt;/code&amp;gt; auf. Nach dem Setzen werden Public Key, Host und Project ID aus der DSN gelesen und in den darunterliegenden Feldern angezeigt.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Demo-dsn.svg|850px|DSN-Konfiguration im Demo-Fenster]]&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Set DSN&amp;lt;/code&amp;gt; initialisiert Sentry mit der eingegebenen DSN. Quelle: &amp;lt;code&amp;gt;FSY_Demo.setDSN.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$init(iDSN)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iDSN.$objinitval as con(kSq,iDSN,kSq)&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$showmessage(&#039;DSN set and Sentry initialized!&#039;,&#039;Info&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$redraw()&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== DB Status anzeigen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FSY_Demo.$displayDBState&amp;lt;/code&amp;gt; zeigt, ob die SQLite Session verbunden ist. Quelle: &amp;lt;code&amp;gt;FSY_Demo.$displayDBState&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tOSLSession.$state Returns dbState&lt;br /&gt;
If dbState=&#039;kSessionStateLoggedOff&#039;&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Logged Off&#039;&lt;br /&gt;
Else If dbState=&#039;kSessionStateLoggedOn&#039;&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Logged On&#039;&lt;br /&gt;
Else&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Unkown DB State&#039;&lt;br /&gt;
End If&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$redraw()&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Demo-Datenbank erstellen ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Create Database&amp;lt;/code&amp;gt; ruft &amp;lt;code&amp;gt;ODatabaseHandler.$DBFirstInit&amp;lt;/code&amp;gt; auf. Quelle: &amp;lt;code&amp;gt;FSY_Demo.createDB.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Setup the DB&lt;br /&gt;
	Do tODatabaseHandler.$DBFirstInit() Returns err&lt;br /&gt;
	If err=0&lt;br /&gt;
		Do $cinst.$showmessage(&#039;DB successfully created!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Else&lt;br /&gt;
		Do $cinst.$showmessage(&#039;Error while creating the DB. Make sure that the DB does not already exist.&#039;,&#039;Info&#039;)&lt;br /&gt;
	End If&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$displayDBState()&lt;br /&gt;
	&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Datenbank wird im Arbeitsverzeichnis der Library angelegt. Quelle: &amp;lt;code&amp;gt;ODatabaseHandler.$getWorkingDir&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Quit method con(FileOps.$parentdir($clib.$pathname),pathsep())&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Demo-DB enthält unter anderem:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;dperson&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;drelease&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;dvcs&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a message&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.message.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Log auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a log&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.log.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureLog(&#039;Uh oh this is a Log because something went wrong&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exception auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger an exception&amp;lt;/code&amp;gt; bereitet eine Row und eine List vor und ruft anschließend &amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt; auf. Quelle: &amp;lt;code&amp;gt;FSY_Demo.exception.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do iDummyRow.$define(id,name)&lt;br /&gt;
	Calculate iDummyRow.id as 22&lt;br /&gt;
	Calculate iDummyRow.name as &#039;Tom&#039;&lt;br /&gt;
	&lt;br /&gt;
	Do iDummyList.$define(id,weekday)&lt;br /&gt;
	Do iDummyList.$add(1,&#039;Monday&#039;)&lt;br /&gt;
	Do iDummyList.$add(2,&#039;Tuesday&#039;)&lt;br /&gt;
	Do iDummyList.$add(3,&#039;Wednesday&#039;)&lt;br /&gt;
	Do iDummyList.$add(4,&#039;Thursday&#039;)&lt;br /&gt;
	Do iDummyList.$add(5,&#039;Friday&#039;)&lt;br /&gt;
	Do iDummyList.$add(6,&#039;Saturday&#039;)&lt;br /&gt;
	Do iDummyList.$add(7,&#039;Sunday&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Calculate iDummyList.$line as 5&lt;br /&gt;
	&lt;br /&gt;
	Do iODummy.$dummyMethod(&#039;Important Value&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt; sendet die Exception. Quelle: &amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#In here is some logic&lt;br /&gt;
#This logic would produce an error&lt;br /&gt;
#We send all this information to Sentry&lt;br /&gt;
&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&lt;br /&gt;
Quit method 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deprecated Call auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a deprecated call&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.deprecatedCall.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureDeprecatedCall()&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception Button ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Trigger an SQLException&amp;lt;/code&amp;gt; ist im Export vorhanden, enthält aber noch keinen fertigen Demo-Code. Quelle: &amp;lt;code&amp;gt;FSY_Demo.sqlException.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Code need&#039;s to be written&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Dokumentation der SQL-Erfassung siehe [[#Events erfassen|03 Events erfassen]].&lt;br /&gt;
&lt;br /&gt;
== API Reference ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite dokumentiert die produktiv relevanten Methoden von &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== OSentryHL ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ist die empfohlene Klasse für Applikationscode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$init(pDSN)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Initialisiert das interne &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;-Objekt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init of the main sentry object&lt;br /&gt;
Do iOSentry.$init(pDSN)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureMessage(pMessage)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet eine einfache Info-Message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an Info Message&lt;br /&gt;
Do iOSentry.$captureException(pMessage,3,,&#039;info&#039;,kFalse,,kFalse) Returns code&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureException(pErrorText,pErrorCode,pExcType,pLevel)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet eine generische Exception.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture a generic Exception&lt;br /&gt;
#Add any custom tags / extras&lt;br /&gt;
Do $cinst.$addTag(&#039;Custom Test Tag&#039;,&#039;Euromnis&#039;)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureAnything(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet ein frei konfigurierbares Event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Capture a generic Sentry Report (max configurability)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hinweis: Der Parameter ist im Export als &amp;lt;code&amp;gt;pStacktraveInterface&amp;lt;/code&amp;gt; geschrieben.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureLog(pErrorText)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet ein Log-Event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a Log Sentry Report&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;Log&#039;,&#039;warning&#039;,1,0,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureDeprecatedCall()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Meldet die Ausführung eines veralteten Codepfads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureSQLException(pErrorText,pStat)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Meldet einen SQL-Fehler mit SQL-Text und nativer Datenbankfehlermeldung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addTag(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt einen Tag für das nächste Event hinzu.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add a Tag to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addTag(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addExtra(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt ein Extra für das nächste Event hinzu.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add an Extra to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addExtra(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setStatus(pStatus)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Aktiviert oder deaktiviert Sentry.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Toggels Sentry on or off&lt;br /&gt;
Do iOSentry.$setStatus(pStatus)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setUser()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt im Export feste [[#Demo Library|Demo]]-Userdaten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Set the User which should be linked to the Sentry Issue&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte diese Methode parametrisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== OSentry ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; ist die Low-Level-Klasse für Payload-Erzeugung und Versand.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$init(pDSN)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parst die DSN in Protokoll, Public Key, Host und Project ID.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraceInterface,pUserInterface,pExceptionInterface)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt JSON, sendet es an Sentry und behandelt Fehlerfälle.&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Default !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; ||  || Message&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; ||  || Fehlercode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExcType&amp;lt;/code&amp;gt; ||  || Exception-Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pLevel&amp;lt;/code&amp;gt; ||  || &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pStacktraceInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || [[#Stacktrace und Kontext|Stacktrace]] senden&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pUserInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || [[#Tags, Extras und User-Kontext|User-Kontext]] senden&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExceptionInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || Exception Interface senden&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateJson(...)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den Sentry JSON Payload als Binary.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateStacktraceInterface(pCulprit)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den Omnis-[[#Stacktrace und Kontext|Stacktrace]] inklusive Variablen und Kontextzeilen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateExceptionInterface(pType,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt das Sentry Exception Interface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Generate Row to store in the JSON&lt;br /&gt;
Do exceptionRow.$define(type,value,stacktrace)&lt;br /&gt;
Calculate exceptionRow.type as pType&lt;br /&gt;
Calculate exceptionRow.value as pValue&lt;br /&gt;
Calculate exceptionRow.stacktrace as &#039;sentry.interfaces.stacktrace&#039; ## Tells the exception interface that a stacktrace is passed aswell&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateUserInterface()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den [[#Tags, Extras und User-Kontext|User-Kontext]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addTag(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt einen Tag zur internen Tag-Liste hinzu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addExtra(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt ein Extra zur internen Extra-Liste hinzu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$clearList()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Leert [[#Tags, Extras und User-Kontext|Tags und Extras]] nach einem Request.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setUserData(pID,pName,pEmail)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt Userdaten für den nächsten Request.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setProxy(pProxyHost,pProxyPort)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt Proxy-Informationen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setStatus(pStatus)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt den Sentry-Status.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Toggels Sentry Reports on or off&lt;br /&gt;
Calculate iStatus as pStatus&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$writeJSON(pJSON,pBuffer)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Schreibt fehlgeschlagene Reports lokal in eine Datei.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$getUnixTimestamp()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Gibt den aktuellen UNIX Timestamp zurück.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateUUID()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt eine UUID für die Sentry Event ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Genereates a UUID for the issue id&lt;br /&gt;
Quit method OW3.$makeuuid(kFalse)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Es erscheinen keine Events in Sentry ===&lt;br /&gt;
&lt;br /&gt;
Prüfe zuerst, ob Sentry aktiv ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$setStatus(1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; beendet sich sofort, wenn der Status &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; oder leer ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Check if Sentry is enabled&lt;br /&gt;
If iStatus=0|isclear(iStatus)&lt;br /&gt;
	Quit method 0&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Die DSN ist falsch ===&lt;br /&gt;
&lt;br /&gt;
Prüfe, ob die DSN korrekt aus Sentry kopiert wurde. &amp;lt;code&amp;gt;OSentry.$init&amp;lt;/code&amp;gt; erwartet eine DSN, aus der Public Key, Host und Project ID gelesen werden können.&lt;br /&gt;
&lt;br /&gt;
Nach dem Setzen der DSN sollten in der [[#Demo Library|Demo-Library]] folgende Felder gefüllt sein:&lt;br /&gt;
&lt;br /&gt;
* Host&lt;br /&gt;
* Public Key&lt;br /&gt;
* Project ID&lt;br /&gt;
&lt;br /&gt;
=== Netzwerk oder Proxy blockiert den Request ===&lt;br /&gt;
&lt;br /&gt;
Wenn die Anwendung keinen direkten Zugriff auf Sentry hat, setze einen Proxy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.iOSentry.$setProxy(&#039;proxy.example.local&#039;,&#039;8080&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Intern wird der Proxy vor dem HTTP Request gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
If not(isclear(iProxyHost))&amp;amp;not(isclear(iProxyPort))&lt;br /&gt;
	HTTPSetProxyServer (iProxyHost,iProxyPort)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Report wird lokal gespeichert ===&lt;br /&gt;
&lt;br /&gt;
Wenn &amp;lt;code&amp;gt;HTTPPost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HTTPSend&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;HTTPRead&amp;lt;/code&amp;gt; fehlschlägt, speichert OSentry den Report lokal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Calculate path as sys(115)&lt;br /&gt;
Calculate filename as con(&#039;Sentryreport_&#039;,$cinst.$getUnixTimestamp(),&#039;.json&#039;)&lt;br /&gt;
Do fOP.$createfile(con(path,filename)) Returns err&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Suche im Omnis-Installationsordner nach Dateien mit dem Namen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Sentryreport_&amp;lt;timestamp&amp;gt;.json&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sentry antwortet nicht mit 200 OK ===&lt;br /&gt;
&lt;br /&gt;
Wenn die HTTP-Antwort kein &amp;lt;code&amp;gt;200 OK&amp;lt;/code&amp;gt; enthält, wird der JSON Report ebenfalls lokal gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPRead (Socket,Buffer) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0|not(pos(&#039;200 OK&#039;,Buffer))&lt;br /&gt;
	# JSON may be corrupted or contains errors -&amp;gt; save json and the buffer as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,Buffer)&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -3&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mögliche Ursachen:&lt;br /&gt;
&lt;br /&gt;
* falsche Project ID&lt;br /&gt;
* falscher Public Key&lt;br /&gt;
* ungültige DSN&lt;br /&gt;
* JSON Payload wird von Sentry abgelehnt&lt;br /&gt;
* Netzwerk-Gateway verändert den Request&lt;br /&gt;
&lt;br /&gt;
=== Tags oder Extras erscheinen beim falschen Event ===&lt;br /&gt;
&lt;br /&gt;
[[#Tags, Extras und User-Kontext|Tags und Extras]] werden für den nächsten Request gesammelt. Nach erfolgreichem Request werden sie gelöscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iTagList.$clear()&lt;br /&gt;
Do iExtraList.$clear()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn ein Request fehlschlägt, wird ebenfalls aufgeräumt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$clearList()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prüfe trotzdem, ob in eigenen Wrapper-Methoden Tags und Extras direkt vor dem passenden Capture-Aufruf gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== User-Kontext zeigt Demo-Daten ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL.$setUser&amp;lt;/code&amp;gt; verwendet im Export feste Testdaten:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte die Methode parametrisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(pUserID,pUserName,pUserEmail)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception Demo-Button funktioniert nicht ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Trigger an SQLException&amp;lt;/code&amp;gt; ist im Export noch nicht implementiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Code need&#039;s to be written&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die produktive Methode für SQL-Fehler ist aber vorhanden. Siehe auch [[#Events erfassen|Events erfassen]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureSQLException(&#039;SQL statement failed&#039;,stat)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Zu viele Events ===&lt;br /&gt;
&lt;br /&gt;
Sentry kann sehr schnell viele Events sammeln. Verwende für produktive Systeme:&lt;br /&gt;
&lt;br /&gt;
* klare Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
* sinnvolle Levels&lt;br /&gt;
* gezielte [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* keine Events in sehr häufigen Schleifen&lt;br /&gt;
* keine rein informativen Debug-Events ohne Nutzen&lt;br /&gt;
&lt;br /&gt;
=== Sensible Daten ===&lt;br /&gt;
&lt;br /&gt;
[[#Stacktrace und Kontext|Stacktrace]], Parameter, Instance Variablen, SQL-Text und [[#Tags, Extras und User-Kontext|Extras]] können sensible Daten enthalten. Prüfe vor produktiver Nutzung:&lt;br /&gt;
&lt;br /&gt;
* Welche Variablen werden übertragen?&lt;br /&gt;
* Enthalten SQL-Statements personenbezogene Daten?&lt;br /&gt;
* Werden Tokens oder Passwörter in Extras geschrieben?&lt;br /&gt;
* Sollen bestimmte Werte maskiert werden?&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Sentry&amp;diff=9527</id>
		<title>Sentry</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Sentry&amp;diff=9527"/>
		<updated>2026-06-12T14:05:39Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- MediaWiki source for page: Sentry --&amp;gt;&lt;br /&gt;
&amp;lt;!-- Upload required files before publishing: Sentry-issue.png, Sentry-stack.png, Sentry-tags.png, Sentry-projects.png, Demo-window.svg, Demo-dsn.svg --&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Überblick ==&lt;br /&gt;
&lt;br /&gt;
OSentry ist ein REST-API-Konnektor von Omnis Studio zu Sentry. Der Konnektor sendet Fehler, Messages, Logs und Laufzeitkontext aus Omnis-Anwendungen an Sentry, damit Probleme in produktiven Systemen sichtbar, gruppierbar und analysierbar werden.&lt;br /&gt;
&lt;br /&gt;
Diese Dokumentation beschreibt die [[#Installation|Installation]], die Nutzung in bestehenden Omnis-Anwendungen, die Definition eigener standardisierter Exception-Typen, die interne Struktur und die [[#Demo Library|Demo-Library]].&lt;br /&gt;
&lt;br /&gt;
=== Inhalt ===&lt;br /&gt;
&lt;br /&gt;
* [[#Installation|01 Installation]]&lt;br /&gt;
* [[#Quickstart|02 Quickstart]]&lt;br /&gt;
* [[#Events erfassen|03 Events erfassen]]&lt;br /&gt;
* [[#Eigene Exceptions standardisieren|04 Eigene Exceptions standardisieren]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|05 Tags Extras und User]]&lt;br /&gt;
* [[#Stacktrace und Kontext|06 Stacktrace und Kontext]]&lt;br /&gt;
* [[#Interne Architektur|07 Interne Architektur]]&lt;br /&gt;
* [[#Demo Library|08 Demo Library]]&lt;br /&gt;
* [[#API Reference|09 API Reference]]&lt;br /&gt;
* [[#Troubleshooting|10 Troubleshooting]]&lt;br /&gt;
&lt;br /&gt;
=== Kernidee ===&lt;br /&gt;
&lt;br /&gt;
OSentry besteht aus zwei produktiv relevanten Klassen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;: High-Level-Adapter für die Anwendung. Diese Klasse sollte von normalem Applikationscode aufgerufen werden.&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;: Low-Level-Adapter für DSN-Parsing, JSON-Erzeugung, [[#Stacktrace und Kontext|Stacktrace]]-Aufbereitung und HTTP-Kommunikation mit Sentry.&lt;br /&gt;
&lt;br /&gt;
Die Anwendung arbeitet im Normalfall mit &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;. Dadurch bleiben Sentry-spezifische Details zentral gekapselt und neue standardisierte Exception-Typen können als eigene Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Hauptfeatures ===&lt;br /&gt;
&lt;br /&gt;
* Direkte Anbindung von Omnis Studio an Sentry über REST API und DSN&lt;br /&gt;
* Erfassen von Exceptions, Messages, Logs und SQL-Fehlern&lt;br /&gt;
* Unterstützung der Sentry-Level &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
* Automatische Omnis-Kontextinformationen&lt;br /&gt;
* Omnis-[[#Stacktrace und Kontext|Stacktrace]] mit Klassen, Methoden, Zeilen und Variablen&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]] für Filterung und Gruppierung&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]] für zusätzliche Diagnoseinformationen&lt;br /&gt;
* Optionaler [[#Tags, Extras und User-Kontext|User-Kontext]]&lt;br /&gt;
* Proxy-Unterstützung&lt;br /&gt;
* Aktivieren und Deaktivieren der Sentry-Übertragung&lt;br /&gt;
* Lokales Speichern von Reports bei Übertragungsfehlern&lt;br /&gt;
&lt;br /&gt;
=== Weiterführende Links ===&lt;br /&gt;
&lt;br /&gt;
* [https://sentry.io/welcome/ Sentry Website]&lt;br /&gt;
* [https://sentry.io/signup/ Sentry Account erstellen]&lt;br /&gt;
* [https://develop.sentry.dev/self-hosted/ Sentry self-hosted]&lt;br /&gt;
&lt;br /&gt;
=== Screenshots ===&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-issue.png|900px|Sentry Issue-Übersicht]]&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite beschreibt, wie OSentry in eine bestehende Omnis-Anwendung integriert wird.&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* Omnis Studio Anwendung&lt;br /&gt;
* Sentry Account oder self-hosted Sentry Installation&lt;br /&gt;
* Ein Sentry-Projekt mit SDK-Typ &amp;lt;code&amp;gt;Other&amp;lt;/code&amp;gt;&lt;br /&gt;
* Die DSN des Sentry-Projekts&lt;br /&gt;
* Netzwerkzugriff auf Sentry&lt;br /&gt;
&lt;br /&gt;
Die exportierte [[#Demo Library|Demo-Library]] wurde mit Omnis &amp;lt;code&amp;gt;11.1&amp;lt;/code&amp;gt; erstellt.&lt;br /&gt;
&lt;br /&gt;
=== Sentry-Projekt erstellen ===&lt;br /&gt;
&lt;br /&gt;
# In Sentry ein neues Projekt erstellen.&lt;br /&gt;
# Als SDK &amp;lt;code&amp;gt;Other&amp;lt;/code&amp;gt; auswählen.&lt;br /&gt;
# Die DSN des Projekts kopieren.&lt;br /&gt;
&lt;br /&gt;
Die DSN wird beim Initialisieren verwendet. &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; zerlegt sie intern in Public Key, Host und Project ID.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-projects.png|900px|Sentry Projektübersicht]]&lt;br /&gt;
&lt;br /&gt;
=== Klassen kopieren ===&lt;br /&gt;
&lt;br /&gt;
Kopiere die folgenden Klassen in deine bestehende Omnis-Library:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Demo-spezifischen Klassen sind für die produktive Integration nicht erforderlich. Damit sind die übrigen Klassen der Demo-Library gemeint, zum Beispiel &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt;. Diese Klassen dienen nur dazu, die [[#Demo Library|Demo-Library]] mit Fenster, SQLite-Testdaten und Beispielaufrufen auszuführen.&lt;br /&gt;
&lt;br /&gt;
=== Task Variable anlegen ===&lt;br /&gt;
&lt;br /&gt;
Lege in deiner Startup Task eine Task Variable an:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Name !! Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; sollte als global erreichbarer Singleton der Anwendung verwendet werden. In Omnis ist dafür eine Task Variable sinnvoll, weil sie von Fenstern, Objektklassen und zentralen Error-Handlern aus konsistent erreichbar ist. Dadurch gibt es genau eine aktive Sentry-Konfiguration mit einer DSN, einem Status, optionalen Proxy-Daten und gemeinsamen Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im [[#Demo Library|Demo-Projekt]] ist diese Variable in &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; definiert.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung im Startup Task ===&lt;br /&gt;
&lt;br /&gt;
Initialisiere &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; beim Start deiner Anwendung mit der DSN deines Sentry-Projekts:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;&amp;lt;DSN&amp;gt;&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die [[#Demo Library|Demo-Library]] ruft im Startup Task ebenfalls die Initialisierung auf. Quelle: &amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init Sentry on lbs startup&lt;br /&gt;
Do tSentry.$init()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In einer produktiven Anwendung sollte die DSN explizit oder aus einer Konfiguration übergeben werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;https://PUBLIC_KEY@sentry.io/PROJECT_ID&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; Speichere die DSN in einer Datenbank, einer Konfigurationstabelle oder einem Config File. So kann sie pro Kunde, Umgebung oder Installation geändert werden, ohne die Library neu auszuliefern.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Testcall ===&lt;br /&gt;
&lt;br /&gt;
Nach der Initialisierung kann ein erstes Testevent gesendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello World!&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles korrekt eingerichtet ist, erscheint das Event im Sentry-Projekt.&lt;br /&gt;
&lt;br /&gt;
=== Proxy konfigurieren ===&lt;br /&gt;
&lt;br /&gt;
Falls die Anwendung in einem geschützten Netzwerk läuft, kann ein Proxy gesetzt werden. Die Methode befindet sich im Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.iOSentry.$setProxy(&#039;proxy.example.local&#039;,&#039;8080&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die interne Implementierung setzt den Proxy vor dem HTTP-Request:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Configure proxy; needed when sending data out of secured networks&lt;br /&gt;
If not(isclear(iProxyHost))&amp;amp;not(isclear(iProxyPort))&lt;br /&gt;
	HTTPSetProxyServer (iProxyHost,iProxyPort)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sentry aktivieren oder deaktivieren ===&lt;br /&gt;
&lt;br /&gt;
OSentry kann zentral ein- oder ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #3366cc; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Empfehlung:&#039;&#039;&#039; Deaktiviere Sentry in der Entwicklungs-Version standardmäßig oder verwende eine separate Entwicklungs-DSN. So landen lokale Tests, Debug-Fehler und absichtlich ausgelöste Exceptions nicht im produktiven Sentry-Projekt.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$setStatus(1)     ## aktiv&lt;br /&gt;
Do tSentry.$setStatus(0)     ## inaktiv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; wird vor dem Senden geprüft:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Check if Sentry is enabled&lt;br /&gt;
If iStatus=0|isclear(iStatus)&lt;br /&gt;
	Quit method 0&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite zeigt die minimale Integration in eine bestehende Omnis-Anwendung.&lt;br /&gt;
&lt;br /&gt;
=== Klassen übernehmen ===&lt;br /&gt;
&lt;br /&gt;
Kopiere &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; in deine Library.&lt;br /&gt;
&lt;br /&gt;
=== Task Variable erstellen ===&lt;br /&gt;
&lt;br /&gt;
In der Startup Task:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Name !! Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sentry initialisieren ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;https://PUBLIC_KEY@sentry.io/PROJECT_ID&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL.$init&amp;lt;/code&amp;gt; delegiert an das Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init of the main sentry object&lt;br /&gt;
Do iOSentry.$init(pDSN)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message senden ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die [[#Demo Library|Demo-Library]] verwendet genau diesen Aufruf im Button &amp;lt;code&amp;gt;Trigger a message&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.message.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exception senden ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== In Sentry prüfen ===&lt;br /&gt;
&lt;br /&gt;
In Sentry sollte anschließend ein neues Event sichtbar sein. Je nach Event-Typ enthält es:&lt;br /&gt;
&lt;br /&gt;
* Message&lt;br /&gt;
* Level&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|User-Kontext]]&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]]&lt;br /&gt;
* Omnis-Kontextinformationen&lt;br /&gt;
&lt;br /&gt;
== Events erfassen ==&lt;br /&gt;
&lt;br /&gt;
OSentryHL ist die empfohlene Einstiegsschicht für Applikationscode. Die Klasse bietet sprechende Methoden für typische Event-Arten und ruft intern &amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
&lt;br /&gt;
=== Message ===&lt;br /&gt;
&lt;br /&gt;
Eine einfache Information wird mit &amp;lt;code&amp;gt;$captureMessage&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello World!&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an Info Message&lt;br /&gt;
Do iOSentry.$captureException(pMessage,3,,&#039;info&#039;,kFalse,,kFalse) Returns code&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Level: &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;&lt;br /&gt;
* Kein [[#Stacktrace und Kontext|Stacktrace]]&lt;br /&gt;
* Kein [[#Tags, Extras und User-Kontext|User Interface]]&lt;br /&gt;
* Geeignet für einfache Statusmeldungen oder technische Hinweise&lt;br /&gt;
&lt;br /&gt;
=== Log ===&lt;br /&gt;
&lt;br /&gt;
Ein Log-Event wird mit &amp;lt;code&amp;gt;$captureLog&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureLog(&#039;Uh oh this is a Log because something went wrong&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a Log Sentry Report&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;Log&#039;,&#039;warning&#039;,1,0,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Level: &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]] aktiv&lt;br /&gt;
* Exception Interface in diesem Wrapper deaktiviert&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|User Interface]] aktiv&lt;br /&gt;
&lt;br /&gt;
=== Generische Exception ===&lt;br /&gt;
&lt;br /&gt;
Eine generische Exception wird mit &amp;lt;code&amp;gt;$captureException&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture a generic Exception&lt;br /&gt;
#Add any custom tags / extras&lt;br /&gt;
Do $cinst.$addTag(&#039;Custom Test Tag&#039;,&#039;Euromnis&#039;)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; || Text, der in Sentry als Message sichtbar ist&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; || Fehlercode oder fachlicher Code&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExcType&amp;lt;/code&amp;gt; || Exception-Typ für Benennung und Gruppierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pLevel&amp;lt;/code&amp;gt; || Sentry-Level&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Gültige Levels:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception ===&lt;br /&gt;
&lt;br /&gt;
SQL-Fehler können mit &amp;lt;code&amp;gt;$captureSQLException&amp;lt;/code&amp;gt; gemeldet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureSQLException(&#039;SQL statement failed&#039;,stat)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Fügt die Datenbank als [[#Tags, Extras und User-Kontext|Tag]] hinzu&lt;br /&gt;
* Fügt SQL-Text als [[#Tags, Extras und User-Kontext|Extra]] hinzu&lt;br /&gt;
* Fügt native Datenbankfehlermeldung als [[#Tags, Extras und User-Kontext|Extra]] hinzu&lt;br /&gt;
* Sendet das Event als &amp;lt;code&amp;gt;SQL-Exception&amp;lt;/code&amp;gt; mit Level &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deprecated Call ===&lt;br /&gt;
&lt;br /&gt;
Veraltete Codepfade können gezielt gemeldet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureDeprecatedCall()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Wrapper eignet sich, um zu erkennen, ob alter Code in produktiven Systemen noch ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
=== Frei konfigurierbares Event ===&lt;br /&gt;
&lt;br /&gt;
Für Sonderfälle gibt es &amp;lt;code&amp;gt;$captureAnything&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureAnything(&#039;Text&#039;,1001,&#039;Custom Type&#039;,&#039;error&#039;,kTrue,kTrue,kTrue)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Capture a generic Sentry Report (max configurability)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Methode bietet maximale Flexibilität. Für wiederkehrende Exception-Typen sollte aber eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; angelegt werden. Siehe [[#Eigene Exceptions standardisieren|04 Eigene Exceptions standardisieren]].&lt;br /&gt;
&lt;br /&gt;
== Eigene Exceptions standardisieren ==&lt;br /&gt;
&lt;br /&gt;
Wenn ein Exception-Typ mehrfach in der Anwendung vorkommt, sollte er nicht überall manuell mit &amp;lt;code&amp;gt;$captureException&amp;lt;/code&amp;gt; aufgebaut werden. Besser ist eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dadurch entsteht eine zentrale, wiederverwendbare Definition für:&lt;br /&gt;
&lt;br /&gt;
* Exception-Typ&lt;br /&gt;
* Sentry-Level&lt;br /&gt;
* Fehlercode&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]]&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]]/[[#Tags, Extras und User-Kontext|User]]/Exception Interface&lt;br /&gt;
&lt;br /&gt;
Die automatisch gesetzten [[#Tags, Extras und User-Kontext|Tags und Extras]] aus &amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; müssen in solchen Wrappern nicht erneut ergänzt werden. Eigene Exception-Methoden setzen nur zusätzliche Werte, die für diesen standardisierten Exception-Typ relevant sind.&lt;br /&gt;
&lt;br /&gt;
=== Warum über OSentryHL? ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ist die Abstraktionsschicht für Applikationscode. Sie kapselt die Details von &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und sorgt dafür, dass Aufrufe in der Anwendung kurz und konsistent bleiben.&lt;br /&gt;
&lt;br /&gt;
Bestehende Beispiele aus &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Empfohlenes Muster ===&lt;br /&gt;
&lt;br /&gt;
Für jeden standardisierten Exception-Typ wird eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; erstellt.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a validation exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Field&#039;,pField)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Invalid Value&#039;,pValue)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,2001,&#039;Validation-Exception&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mögliche Parameter der neuen Methode:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Beispiel !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;Invalid customer number&#039;&amp;lt;/code&amp;gt; || Sentry Message&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pModule&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;Customer&#039;&amp;lt;/code&amp;gt; || Filterbarer Tag&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pField&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;cu_number&#039;&amp;lt;/code&amp;gt; || Diagnoseinformation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pValue&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;ABC&#039;&amp;lt;/code&amp;gt; || Diagnoseinformation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der Applikationscode bleibt dadurch einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureValidationException(&#039;Invalid customer number&#039;,&#039;Customer&#039;,&#039;cu_number&#039;,cu_number)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel: Business Rule Exception ===&lt;br /&gt;
&lt;br /&gt;
Neue Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a business rule violation&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addTag(&#039;Business Rule&#039;,pRuleName)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Details&#039;,pDetails)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aufruf in der Anwendung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureBusinessRuleViolation(&#039;Invoice cannot be posted&#039;,&#039;Invoice&#039;,&#039;PostingAllowed&#039;,&#039;Invoice is missing customer&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel: Integration Exception ===&lt;br /&gt;
&lt;br /&gt;
Neue Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an integration exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Integration&#039;,pSystem)&lt;br /&gt;
Do $cinst.$addTag(&#039;Endpoint&#039;,pEndpoint)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Payload&#039;,pPayload)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Response&#039;,pResponse)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,4001,&#039;Integration-Exception&#039;,&#039;error&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aufruf in der Anwendung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureIntegrationException(&#039;External API request failed&#039;,&#039;ERP&#039;,&#039;/api/customer&#039;,jsonPayload,responseText)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Namenskonventionen ===&lt;br /&gt;
&lt;br /&gt;
Empfehlung für neue Methoden:&lt;br /&gt;
&lt;br /&gt;
* Methodenname beginnt mit &amp;lt;code&amp;gt;$capture&amp;lt;/code&amp;gt;&lt;br /&gt;
* Der fachliche Typ steht im Methodennamen&lt;br /&gt;
* Der Sentry Exception Type ist stabil und ändert sich nicht laufend&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]] sind kurz und filterbar&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]] dürfen länger sein und Diagnoseinformationen enthalten&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureValidationException&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureBusinessRuleViolation&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureIntegrationException&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$capturePermissionViolation&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureConfigurationError&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error Codes ===&lt;br /&gt;
&lt;br /&gt;
Verwende feste Fehlercodes für standardisierte Exception-Typen. Dadurch können Events in Sentry besser gefiltert und wiedererkannt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Code !! Exception Type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Validation-Exception&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Business-Rule-Violation&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Integration-Exception&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;5001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Configuration-Error&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wann nicht standardisieren? ===&lt;br /&gt;
&lt;br /&gt;
Nicht jeder Einzelfall braucht eine eigene Methode. Für einmalige technische Tests oder sehr spezielle Fälle reicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald ein Exception-Typ aber mehrfach vorkommt oder fachlich relevant ist, sollte er als eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
== Tags, Extras und User-Kontext ==&lt;br /&gt;
&lt;br /&gt;
Tags, Extras und User-Kontext reichern Sentry-Events mit zusätzlichen Informationen an. Diese Informationen helfen beim Filtern, Gruppieren und Analysieren.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-tags.png|900px|Sentry Tags und User-Kontext]]&lt;br /&gt;
&lt;br /&gt;
=== Tags ===&lt;br /&gt;
&lt;br /&gt;
Tags sind kurze, filterbare Werte.&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* Datenbank&lt;br /&gt;
* Kunde&lt;br /&gt;
* Modul&lt;br /&gt;
* Umgebung&lt;br /&gt;
* Error Code&lt;br /&gt;
* Omnis-Version&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add a Tag to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addTag(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Adds a tag to the next request processed&lt;br /&gt;
Do iTagList.$add(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$addTag(&#039;Module&#039;,&#039;Invoice&#039;)&lt;br /&gt;
Do tSentry.$addTag(&#039;Customer&#039;,&#039;10001&#039;)&lt;br /&gt;
Do tSentry.$captureException(&#039;Invoice posting failed&#039;,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Extras ===&lt;br /&gt;
&lt;br /&gt;
Extras sind Detailinformationen, die nicht primär zum Filtern gedacht sind.&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* SQL-Text&lt;br /&gt;
* Native Datenbankfehlermeldung&lt;br /&gt;
* Payload&lt;br /&gt;
* Response Body&lt;br /&gt;
* interne IDs&lt;br /&gt;
* zusätzliche Debug-Informationen&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add an Extra to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addExtra(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Adds extra information to the next request being processed&lt;br /&gt;
Do iExtraList.$add(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel aus der SQL Exception:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Automatische Tags ===&lt;br /&gt;
&lt;br /&gt;
Die folgenden Tags werden bei jedem Event automatisch von &amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; ergänzt. Sie müssen bei eigenen Exceptions nicht erneut gesetzt werden. Eigene Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; sollten nur zusätzliche, fachlich oder technisch relevante Tags hinzufügen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; fügt mehrere Tags automatisch hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add static tags&lt;br /&gt;
Do iTagList.$add(&#039;Omnisversion&#039;,sys(1))&lt;br /&gt;
Calculate systemversionRow as systemversion()&lt;br /&gt;
Do iTagList.$add(&#039;Plattform&#039;,con(sys(8),pick(systemversionRow.server,&#039;&#039;,&#039; SRV&#039;)))&lt;br /&gt;
Do iTagList.$add(&#039;OS Version&#039;,con(systemversionRow.major,&#039;.&#039;,systemversionRow.minor,&#039;.&#039;,systemversionRow.build))&lt;br /&gt;
Do iTagList.$add(&#039;error_code&#039;,pErrorCode)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Automatisch gesendete Tags:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tag !! Herkunft !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Omnisversion&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;sys(1)&amp;lt;/code&amp;gt; || Zeigt, mit welcher Omnis-Version das Event erzeugt wurde&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Plattform&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;sys(8)&amp;lt;/code&amp;gt; und Server-Flag aus &amp;lt;code&amp;gt;systemversion()&amp;lt;/code&amp;gt; || Unterscheidet Plattform und Server Runtime&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OS Version&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;systemversionRow.major/minor/build&amp;lt;/code&amp;gt; || Zeigt die Betriebssystemversion&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;error_code&amp;lt;/code&amp;gt; || Parameter &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; || Verbindet das Event mit dem übergebenen Fehlercode&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Beispiel für eine eigene Exception: Der Wrapper muss nicht erneut &amp;lt;code&amp;gt;Omnisversion&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;OS Version&amp;lt;/code&amp;gt; setzen. Er ergänzt nur das, was für diesen Exception-Typ zusätzlich hilfreich ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addTag(&#039;Business Rule&#039;,pRuleName)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Automatische Extras ===&lt;br /&gt;
&lt;br /&gt;
Auch die folgenden Extras werden bei jedem Event automatisch ergänzt. Bei eigenen Exceptions müssen nur zusätzliche Extras gesetzt werden, zum Beispiel ein SQL-Statement, ein Payload oder fachliche Zusatzdaten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; fügt offene Fenster, offene Reports und die aktuelle Printfile hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Static extra 1: All open windows&lt;br /&gt;
Do $root.$iwindows.$makelist($ref.$name) Returns nameList&lt;br /&gt;
For i from 1 to nameList.$linecount step 1&lt;br /&gt;
	Calculate windows as con(windows,&#039;, &#039;,nameList.[i].1)&lt;br /&gt;
End For&lt;br /&gt;
Calculate windows as right(windows,len(windows)-2)&lt;br /&gt;
Do iExtraList.$add(&#039;Open Windows&#039;,windows)&lt;br /&gt;
&lt;br /&gt;
# Static extra 2: All open reports&lt;br /&gt;
Do $root.$ireports.$makelist($ref.$name) Returns nameList&lt;br /&gt;
For i from 1 to nameList.$linecount step 1&lt;br /&gt;
	Calculate reports as con(reports,&#039;, &#039;,nameList.[i].1)&lt;br /&gt;
End For&lt;br /&gt;
Calculate reports as right(reports,len(reports)-2)&lt;br /&gt;
Do iExtraList.$add(&#039;Open Reports&#039;,reports)&lt;br /&gt;
Do iExtraList.$add(&#039;Current Printfile&#039;,$root.$prefs.$printfile)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Automatisch gesendete Extras:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Extra !! Herkunft !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Open Windows&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$iwindows.$makelist($ref.$name)&amp;lt;/code&amp;gt; || Zeigt, welche Fenster im Moment des Events offen waren&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Open Reports&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$ireports.$makelist($ref.$name)&amp;lt;/code&amp;gt; || Zeigt, welche Reports im Moment des Events offen waren&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Current Printfile&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$prefs.$printfile&amp;lt;/code&amp;gt; || Zeigt die aktuell gesetzte Printfile&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Beispiel für zusätzliche Extras in einem eigenen Wrapper:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$addExtra(&#039;Payload&#039;,pPayload)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Response&#039;,pResponse)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,4001,&#039;Integration-Exception&#039;,&#039;error&#039;,1,1,1) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== User-Kontext ===&lt;br /&gt;
&lt;br /&gt;
Der User-Kontext ordnet ein Event einem betroffenen Benutzer zu. In Sentry erscheint dadurch ein eigener User-Bereich, und Events können nach Benutzer gefiltert oder gruppiert werden. Das ist besonders hilfreich, wenn ein Fehler nur bei einzelnen Kunden, Arbeitsplätzen oder Benutzerkonten auftritt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; unterstützt drei User-Felder:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feld !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt; || stabile interne Benutzer-ID oder Kundennummer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;username&amp;lt;/code&amp;gt; || lesbarer Benutzername&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;email&amp;lt;/code&amp;gt; || E-Mail-Adresse, falls sie übertragen werden darf&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der User-Kontext wird nur in das Event geschrieben, wenn das User Interface beim Capture-Aufruf aktiviert ist. Die Standardmethode &amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; hat &amp;lt;code&amp;gt;pUserInterface&amp;lt;/code&amp;gt; standardmäßig auf &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt;. Einzelne High-Level-Methoden können das bewusst deaktivieren, zum Beispiel &amp;lt;code&amp;gt;$captureMessage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; kann User-Daten an das Event anhängen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Sets userinformation for the next request being processed&lt;br /&gt;
Calculate iUserID as pID&lt;br /&gt;
Calculate iUserName as pName&lt;br /&gt;
Calculate iUserEmail as pEmail&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das User Interface wird so generiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Create user data row&lt;br /&gt;
Do UserdataRow.$define(id,email,username)&lt;br /&gt;
&lt;br /&gt;
Calculate UserdataRow.id as iUserID&lt;br /&gt;
Calculate UserdataRow.email as iUserEmail&lt;br /&gt;
Calculate UserdataRow.username as iUserName&lt;br /&gt;
&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;user&#039;,&#039;&#039;)&lt;br /&gt;
Do JSON.$setobject(&#039;user&#039;,UserdataRow)&lt;br /&gt;
&lt;br /&gt;
Calculate jsonString as OJSON.$formatjson(JSON.$getjson())&lt;br /&gt;
&lt;br /&gt;
Quit method jsonString&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die aktuelle Demo-Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; verwendet feste Testdaten. Quelle: &amp;lt;code&amp;gt;OSentryHL.$setUser&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Set the User which should be linked to the Sentry Issue&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte diese Methode angepasst und parametrisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(pUserID,pUserName,pUserEmail)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Empfohlen ist, den User nach Login oder beim Wechsel des aktiven Benutzers zentral zu setzen. Bei anonymen oder sensiblen Installationen kann statt Name und E-Mail auch nur eine interne ID oder ein pseudonymisierter Wert verwendet werden.&lt;br /&gt;
&lt;br /&gt;
=== Datenschutz ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-left:4px solid #72777d; padding:8px 12px; margin:12px 0; background:#f8f9fa;&amp;quot;&amp;gt;&#039;&#039;&#039;Datenschutz:&#039;&#039;&#039; Prüfe vor produktiver Nutzung, welche Daten an Sentry gesendet werden. Besonders kritisch sind personenbezogene Daten, SQL-Statements, Zugangsdaten, Tokens und interne Pfade.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Besonders kritisch sind:&lt;br /&gt;
&lt;br /&gt;
* personenbezogene Daten&lt;br /&gt;
* Kundendaten&lt;br /&gt;
* SQL-Statements mit Werten&lt;br /&gt;
* Zugangsdaten&lt;br /&gt;
* Tokens&lt;br /&gt;
* interne Pfade&lt;br /&gt;
&lt;br /&gt;
Tags und Extras sollten so gestaltet werden, dass sie für die Fehleranalyse hilfreich sind, aber keine unnötigen sensiblen Daten übertragen.&lt;br /&gt;
&lt;br /&gt;
== Stacktrace und Kontext ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; erzeugt einen Omnis-spezifischen Stacktrace und übergibt ihn an Sentry. Dadurch sieht man in Sentry nicht nur eine Fehlermeldung, sondern auch Klassen, Methoden, Zeilen und Variablenkontext. Ergänzende Informationen zu [[#Tags, Extras und User-Kontext|Tags, Extras und User-Kontext]] stehen auf der separaten Kontext-Seite.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Sentry-stack.png|900px|Sentry Stacktrace mit Omnis-Kontext]]&lt;br /&gt;
&lt;br /&gt;
=== Stack lesen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateStacktraceInterface&amp;lt;/code&amp;gt; verwendet &amp;lt;code&amp;gt;sys(192)&amp;lt;/code&amp;gt;, um den aktuellen Omnis-Stack zu lesen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Clean up the Stacklist (remove OSentry classes from the stack)&lt;br /&gt;
Do sys(192) Returns sys192List&lt;br /&gt;
For sys192List.$line from 1 to sys192List.$linecount step 1&lt;br /&gt;
	Set reference class to sys192List.classitem&lt;br /&gt;
	If pos(&#039;OSentry&#039;,class.$name)&amp;gt;0|pos(&#039;OSentryHL&#039;,class.$name)&amp;gt;0&lt;br /&gt;
		Do sys192List.[sys192List.$line].$selected.$assign(kTrue)&lt;br /&gt;
	End If&lt;br /&gt;
End For&lt;br /&gt;
Do sys192List.$remove(kListDeleteSelected)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Interne Frames von &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; werden entfernt, damit in Sentry die fachlich relevanten Stellen sichtbar bleiben.&lt;br /&gt;
&lt;br /&gt;
=== SQL-Error Frames entfernen ===&lt;br /&gt;
&lt;br /&gt;
Bestimmte interne SQL-Fehlerframes werden ebenfalls entfernt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Remove some other classes which we do not want to display&lt;br /&gt;
If sys192List.1.method=&#039;$sqlerror&#039;&lt;br /&gt;
	Do sys192List.$remove(1)&lt;br /&gt;
Else If sys192List.1.method=&#039;$statementerror&#039;&lt;br /&gt;
	Do sys192List.$remove(1)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frames erzeugen ===&lt;br /&gt;
&lt;br /&gt;
Für jeden Stack-Eintrag werden Funktion, Zeilennummer und Kontextzeile erzeugt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Loop through every item on the omnis stack&lt;br /&gt;
For sys192List.$line from 1 to sys192List.$linecount step 1&lt;br /&gt;
	Set reference class to sys192List.classitem&lt;br /&gt;
	Calculate className as class.$name&lt;br /&gt;
	&lt;br /&gt;
	# Create the content row&lt;br /&gt;
	Do contentRow.$define(vars,function,pre_context,context_line,lineno,filename,post_context)&lt;br /&gt;
	Calculate contentRow.lineno as sys192List.line&lt;br /&gt;
	Calculate contentRow.filename as testFileName&lt;br /&gt;
	Calculate contentRow.context_line as sys192List.linetext&lt;br /&gt;
	If isclear(sys192List.object)&lt;br /&gt;
		Calculate contentRow.function as con(className,&#039;.&#039;,sys192List.method) ## If it&#039;s a class method&lt;br /&gt;
	Else&lt;br /&gt;
		Calculate contentRow.function as con(className,&#039;.&#039;,sys192List.object,&#039;.&#039;,sys192List.method) ## If it&#039;s a method of an object of a class (e.g. Headedlist)&lt;br /&gt;
	End If&lt;br /&gt;
	Do contentList.$add(contentRow)&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablen aufnehmen ===&lt;br /&gt;
&lt;br /&gt;
Pro Stackframe werden Instance Variablen und Parameter gesammelt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Get all iVars&lt;br /&gt;
Do varList.$define(name,value)&lt;br /&gt;
Set reference class to sys192List.inst&lt;br /&gt;
Do $cinst.$getVars(&#039;ivars&#039;,class) Returns varList&lt;br /&gt;
&lt;br /&gt;
# Get all params&lt;br /&gt;
Calculate paramList as sys192List.params&lt;br /&gt;
For paramList.$line from 1 to paramList.$linecount step 1&lt;br /&gt;
	If not(paramList.value=&#039;(Not empty)&#039;)&lt;br /&gt;
		Do varList.$add(paramList.name,paramList.value)&lt;br /&gt;
	Else&lt;br /&gt;
		Do varList.$add(paramList.name,&#039;(Not empty)&#039;)&lt;br /&gt;
	End If&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pre- und Post-Context ===&lt;br /&gt;
&lt;br /&gt;
OSentry fügt Methodenzeilen vor und nach der aktuellen Zeile hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Pre Context (all method lines before the error occured)&lt;br /&gt;
Set reference method to sys192List.methoditem&lt;br /&gt;
Do precontextList.$define(line)&lt;br /&gt;
For i from 1 to sys192List.line-1 step 1&lt;br /&gt;
	Do precontextList.$add(method.$methodlines.[i].$text)&lt;br /&gt;
End For&lt;br /&gt;
&lt;br /&gt;
# Post Context (all method lines after the error occured&lt;br /&gt;
Do postcontextList.$define(line)&lt;br /&gt;
For i from sys192List.line+1 to method.$methodlines.$count step 1&lt;br /&gt;
	Do postcontextList.$add(method.$methodlines.[i].$text)&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablentypen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$getVars&amp;lt;/code&amp;gt; unterstützt Basisvariablen, Rows und Lists.&lt;br /&gt;
&lt;br /&gt;
Basisvariablen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
If varType=&#039;char&#039;|varType=&#039;boolean&#039;|varType=&#039;integer&#039;|varType=&#039;number&#039;|varType=&#039;date&#039;&lt;br /&gt;
	Calculate varContent as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	Do varList.$add(varName,varContent)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Else If varType=&#039;row&#039;&lt;br /&gt;
	Calculate varRow as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	If varRow.$colcount=0&lt;br /&gt;
		Do varList.$add(varName,&#039;(Empty)&#039;)&lt;br /&gt;
	Else&lt;br /&gt;
		For Z2 from 1 to varRow.$colcount step 1&lt;br /&gt;
			Calculate varContent as con(varContent,varRow.$cols.[Z2].$name,&#039;: &#039;,varRow.[Z2],&#039;, &#039;)&lt;br /&gt;
		End For&lt;br /&gt;
		Do varList.$add(varName,varContent)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lists:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Else If varType=&#039;list&#039;&lt;br /&gt;
	Calculate varListType as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	Calculate varContent as con(&#039;Colcount: &#039;,varListType.$colcount,&#039;, &#039;,&#039;Linecount: &#039;,varListType.$linecount,&#039;, &#039;,&#039;Current Line: &#039;,varListType.$line)&lt;br /&gt;
	If varListType.$linecount=0&amp;amp;varListType.$line=0&amp;amp;varListType.$colcount=0&lt;br /&gt;
		Do varList.$add(varName,&#039;(Empty)&#039;)&lt;br /&gt;
		Calculate varContent as &#039;&#039;&lt;br /&gt;
	Else&lt;br /&gt;
		For Z3 from 1 to varListType.$colcount step 1&lt;br /&gt;
			Calculate colName as varListType.$cols.[Z3].$name&lt;br /&gt;
			Calculate varContent as con(varContent,&#039;  &#039;,colName,&#039;: &#039;,varListType.[colName])&lt;br /&gt;
		End For&lt;br /&gt;
		Do varList.$add(varName,varContent)&lt;br /&gt;
		Calculate varContent as &#039;&#039;&lt;br /&gt;
	End If&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
&lt;br /&gt;
Stacktrace und Variablenkontext sind sehr hilfreich, können aber sensible Daten enthalten. Vor produktiver Nutzung sollte geprüft werden, ob bestimmte Variablen anonymisiert oder ausgeschlossen werden müssen.&lt;br /&gt;
&lt;br /&gt;
== Interne Architektur ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite beschreibt die produktiv relevanten Klassen &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Klassenübersicht ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Rolle&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; || High-Level-Adapter für Applikationscode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; || Low-Level-Adapter für JSON, [[#Stacktrace und Kontext|Stacktrace]] und HTTP&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Startup und Beispiel für Initialisierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Code für [[#Stacktrace und Kontext|Stacktrace]]-Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-DB Initialisierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt; || SQLite Session für [[#Demo Library|Demo]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Empfohlener Aufrufweg ===&lt;br /&gt;
&lt;br /&gt;
Applikationscode sollte &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; verwenden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; delegiert anschließend an &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ablauf eines Events ===&lt;br /&gt;
&lt;br /&gt;
# Applikationscode ruft Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; fügt bei Bedarf [[#Tags, Extras und User-Kontext|Tags und Extras]] hinzu.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ruft &amp;lt;code&amp;gt;iOSentry.$captureException(...)&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; prüft, ob Sentry aktiv ist.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; erzeugt JSON.&lt;br /&gt;
# [[#Stacktrace und Kontext|Stacktrace]], Exception Interface und [[#Tags, Extras und User-Kontext|User Interface]] werden optional ergänzt.&lt;br /&gt;
# HTTP Header und Sentry Auth Header werden erstellt.&lt;br /&gt;
# JSON wird per HTTPS an Sentry gesendet.&lt;br /&gt;
# Bei Erfolg werden [[#Tags, Extras und User-Kontext|Tags und Extras]] geleert.&lt;br /&gt;
# Bei Fehler wird der JSON Report lokal gespeichert.&lt;br /&gt;
&lt;br /&gt;
=== DSN Parsing ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$init&amp;lt;/code&amp;gt; zerlegt die DSN:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Parse the DSN into Public Key, Host and Project ID&lt;br /&gt;
If len(pDSN)&amp;gt;5&lt;br /&gt;
	Calculate iDSN as pDSN&lt;br /&gt;
	Calculate part1 as strtok(&#039;iDSN&#039;,&#039;@&#039;)&lt;br /&gt;
	Calculate iProtocol as strtok(&#039;part1&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iProtocol as left(iProtocol,len(iProtocol)-1)&lt;br /&gt;
	Do strtok(&#039;part1&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iPubKey as strtok(&#039;part1&#039;,&#039;:&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Calculate iHost as strtok(&#039;iDSN&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iProID as iDSN&lt;br /&gt;
	&lt;br /&gt;
	#Save the values for the next startup&lt;br /&gt;
	Calculate $cclass.$ivardefs.iPubKey.$objinitval as con(&#039;&amp;quot;&#039;,iPubKey,&#039;&amp;quot;&#039;)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iHost.$objinitval as con(&#039;&amp;quot;&#039;,iHost,&#039;&amp;quot;&#039;)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iProID.$objinitval as con(&#039;&amp;quot;&#039;,iProID,&#039;&amp;quot;&#039;)&lt;br /&gt;
End If&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== JSON-Erzeugung ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; ist die zentrale Methode für den Payload. Sie setzt unter anderem:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;event_id&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;logger&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;platform&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;culprit&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;timestamp&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sdk&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;message&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;level&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;tags&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;extra&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;exception&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;stacktrace&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auszug:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add all required fields (those are required from the API)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;event_id&#039;,$cinst.$generateUUID()) ## auto generated UUID 4&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;logger&#039;,logger)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;platform&#039;,platform)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;culprit&#039;,culprit)&lt;br /&gt;
#Do JSON.$addmember(&#039;&#039;,&#039;release&#039;,release)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;timestamp&#039;,timestamp)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;sdk&#039;,&#039;&#039;)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;message&#039;,pErrorText)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;level&#039;,pLevel)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;tags&#039;,&#039;&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== HTTP-Kommunikation ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; sendet den erzeugten JSON-Payload an Sentry:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Generate HTTP Auth header&lt;br /&gt;
Begin text block&lt;br /&gt;
Text:Sentry sentry_version=7,&lt;br /&gt;
Text:sentry_timestamp=[$cinst.$getUnixTimestamp()],&lt;br /&gt;
Text:sentry_key=[iPubKey],&lt;br /&gt;
Text:sentry_client=omnis/1.0&lt;br /&gt;
End text block&lt;br /&gt;
Get text block auth&lt;br /&gt;
&lt;br /&gt;
#Generate header list&lt;br /&gt;
Calculate Host as &#039;sentry.io&#039;&lt;br /&gt;
Calculate Url as con(&#039;/api/&#039;,iProID,&#039;/store/&#039;)&lt;br /&gt;
Do HdrList.$define(wert,name)&lt;br /&gt;
Do HdrList.$add(&#039;User-Agent&#039;,&#039;omnis/1.0&#039;)&lt;br /&gt;
Do HdrList.$add(&#039;Content-Type&#039;,&#039;application/json&#039;)&lt;br /&gt;
Do HdrList.$add(&#039;Content-Length&#039;,binlength(json))&lt;br /&gt;
Do HdrList.$add(&#039;X-Sentry-Auth&#039;,auth)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anschließend wird der Request über &amp;lt;code&amp;gt;HTTPPost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HTTPSend&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;HTTPRead&amp;lt;/code&amp;gt; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
=== Fehlerbehandlung beim Senden ===&lt;br /&gt;
&lt;br /&gt;
Wenn der Socket nicht geöffnet werden kann:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPPost (Host,Url,,HdrList,443,kTrue,kTrue) Returns Socket&lt;br /&gt;
If Socket&amp;lt;0&lt;br /&gt;
	#Error when opening connection -&amp;gt; save json as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,con(&#039;Error &#039;,Socket,&#039; when performing HTTPPost&#039;))&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -1&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn das Senden fehlschlägt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPSend (Socket,json) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0&lt;br /&gt;
	# Error while sending data -&amp;gt; save json as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,con(&#039;Erorr &#039;,byteCount,&#039; when performing HTTPSend&#039;))&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -2&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn die Antwort nicht erfolgreich ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPRead (Socket,Buffer) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0|not(pos(&#039;200 OK&#039;,Buffer))&lt;br /&gt;
	# JSON may be corrupted or contains errors -&amp;gt; save json and the buffer as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,Buffer)&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -3&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Lokales Speichern ===&lt;br /&gt;
&lt;br /&gt;
Bei Fehlern wird der JSON Report lokal im Omnis-Installationsordner gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Writes the json and the http buffer to a file in the omnis installation folder&lt;br /&gt;
Calculate path as sys(115)&lt;br /&gt;
Calculate filename as con(&#039;Sentryreport_&#039;,$cinst.$getUnixTimestamp(),&#039;.json&#039;)&lt;br /&gt;
Do fOP.$createfile(con(path,filename)) Returns err&lt;br /&gt;
Do fOP.$writecharacter(kUniTypeUTF8,pJSON) Returns err&lt;br /&gt;
If not(isclear(pBuffer))&lt;br /&gt;
	Do fOP.$writecharacter(kUniTypeUTF8,con(kCr,pBuffer),kTrue) Returns err&lt;br /&gt;
End If&lt;br /&gt;
Do fOP.$closefile()&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cleanup ===&lt;br /&gt;
&lt;br /&gt;
Nach erfolgreichem Senden werden [[#Tags, Extras und User-Kontext|Tags und Extras]] gelöscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Clears all extras and tags =&amp;gt; to be used after a sentry request has successfully been sent&lt;br /&gt;
Do iTagList.$clear()&lt;br /&gt;
Do iExtraList.$clear()&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Demo Library ==&lt;br /&gt;
&lt;br /&gt;
Die Demo-Library zeigt, wie &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; initialisiert wird und wie verschiedene [[#Events erfassen|Event-Typen]] aus einer Omnis-Oberfläche heraus an Sentry gesendet werden.&lt;br /&gt;
&lt;br /&gt;
=== Bestandteile ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; || Initialisiert Sentry, SQLite und öffnet das Demo-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; || Demo-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt; || Erzeugt Demo-Stack für Exception&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; || Erstellt SQLite-Demo-Datenbank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt; || SQLite Session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; || Low-Level-Sentry-Adapter&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; || High-Level-Sentry-Adapter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt; initialisiert Sentry, baut eine SQLite Session auf und öffnet das Demo-Fenster. Quelle: &amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init Sentry on lbs startup&lt;br /&gt;
Do tSentry.$init()&lt;br /&gt;
&lt;br /&gt;
#SQLite Session init&lt;br /&gt;
Do $objects.OSLSession.$newref() Returns tOSLSession&lt;br /&gt;
#Calculate tOSLSession.$opencreate as kTrue&lt;br /&gt;
Calculate workingDir as tODatabaseHandler.$getWorkingDir()&lt;br /&gt;
Do con(workingDir,&#039;Sentry_Test.db&#039;) Returns dbLocation&lt;br /&gt;
Do tOSLSession.$logon(dbLocation,&#039;&#039;,&#039;&#039;,&#039;slsession&#039;) Returns #F&lt;br /&gt;
&lt;br /&gt;
#Open Test Window&lt;br /&gt;
Do $windows.FSY_Demo.$openonce(&#039;*&#039;)&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Demo-Fenster ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; enthält folgende Bereiche:&lt;br /&gt;
&lt;br /&gt;
* DSN Configuration&lt;br /&gt;
* DB Status&lt;br /&gt;
* Actions&lt;br /&gt;
&lt;br /&gt;
Wichtige Felder:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feld !! Datenanbindung&lt;br /&gt;
|-&lt;br /&gt;
| DSN || &amp;lt;code&amp;gt;iDSN&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Host || &amp;lt;code&amp;gt;tSentry.iOSentry.iHost&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Public Key || &amp;lt;code&amp;gt;tSentry.iOSentry.iPubKey&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Project ID || &amp;lt;code&amp;gt;tSentry.iOSentry.iProID&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| DB Status || &amp;lt;code&amp;gt;iCurrentDBStatus&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Datei:Demo-window.svg|850px|Demo-Fenster der OSentry Library]]&lt;br /&gt;
&lt;br /&gt;
=== DSN setzen ===&lt;br /&gt;
&lt;br /&gt;
Die DSN wird im Feld &amp;lt;code&amp;gt;iDSN&amp;lt;/code&amp;gt; erfasst. Der Button &amp;lt;code&amp;gt;Set DSN&amp;lt;/code&amp;gt; ruft anschließend &amp;lt;code&amp;gt;tSentry.$init(iDSN)&amp;lt;/code&amp;gt; auf. Nach dem Setzen werden Public Key, Host und Project ID aus der DSN gelesen und in den darunterliegenden Feldern angezeigt.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Demo-dsn.svg|850px|DSN-Konfiguration im Demo-Fenster]]&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Set DSN&amp;lt;/code&amp;gt; initialisiert Sentry mit der eingegebenen DSN. Quelle: &amp;lt;code&amp;gt;FSY_Demo.setDSN.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$init(iDSN)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iDSN.$objinitval as con(kSq,iDSN,kSq)&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$showmessage(&#039;DSN set and Sentry initialized!&#039;,&#039;Info&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$redraw()&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== DB Status anzeigen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FSY_Demo.$displayDBState&amp;lt;/code&amp;gt; zeigt, ob die SQLite Session verbunden ist. Quelle: &amp;lt;code&amp;gt;FSY_Demo.$displayDBState&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tOSLSession.$state Returns dbState&lt;br /&gt;
If dbState=&#039;kSessionStateLoggedOff&#039;&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Logged Off&#039;&lt;br /&gt;
Else If dbState=&#039;kSessionStateLoggedOn&#039;&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Logged On&#039;&lt;br /&gt;
Else&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Unkown DB State&#039;&lt;br /&gt;
End If&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$redraw()&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Demo-Datenbank erstellen ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Create Database&amp;lt;/code&amp;gt; ruft &amp;lt;code&amp;gt;ODatabaseHandler.$DBFirstInit&amp;lt;/code&amp;gt; auf. Quelle: &amp;lt;code&amp;gt;FSY_Demo.createDB.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Setup the DB&lt;br /&gt;
	Do tODatabaseHandler.$DBFirstInit() Returns err&lt;br /&gt;
	If err=0&lt;br /&gt;
		Do $cinst.$showmessage(&#039;DB successfully created!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Else&lt;br /&gt;
		Do $cinst.$showmessage(&#039;Error while creating the DB. Make sure that the DB does not already exist.&#039;,&#039;Info&#039;)&lt;br /&gt;
	End If&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$displayDBState()&lt;br /&gt;
	&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Datenbank wird im Arbeitsverzeichnis der Library angelegt. Quelle: &amp;lt;code&amp;gt;ODatabaseHandler.$getWorkingDir&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Quit method con(FileOps.$parentdir($clib.$pathname),pathsep())&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Demo-DB enthält unter anderem:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;dperson&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;drelease&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;dvcs&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a message&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.message.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Log auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a log&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.log.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureLog(&#039;Uh oh this is a Log because something went wrong&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exception auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger an exception&amp;lt;/code&amp;gt; bereitet eine Row und eine List vor und ruft anschließend &amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt; auf. Quelle: &amp;lt;code&amp;gt;FSY_Demo.exception.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do iDummyRow.$define(id,name)&lt;br /&gt;
	Calculate iDummyRow.id as 22&lt;br /&gt;
	Calculate iDummyRow.name as &#039;Tom&#039;&lt;br /&gt;
	&lt;br /&gt;
	Do iDummyList.$define(id,weekday)&lt;br /&gt;
	Do iDummyList.$add(1,&#039;Monday&#039;)&lt;br /&gt;
	Do iDummyList.$add(2,&#039;Tuesday&#039;)&lt;br /&gt;
	Do iDummyList.$add(3,&#039;Wednesday&#039;)&lt;br /&gt;
	Do iDummyList.$add(4,&#039;Thursday&#039;)&lt;br /&gt;
	Do iDummyList.$add(5,&#039;Friday&#039;)&lt;br /&gt;
	Do iDummyList.$add(6,&#039;Saturday&#039;)&lt;br /&gt;
	Do iDummyList.$add(7,&#039;Sunday&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Calculate iDummyList.$line as 5&lt;br /&gt;
	&lt;br /&gt;
	Do iODummy.$dummyMethod(&#039;Important Value&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt; sendet die Exception. Quelle: &amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#In here is some logic&lt;br /&gt;
#This logic would produce an error&lt;br /&gt;
#We send all this information to Sentry&lt;br /&gt;
&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&lt;br /&gt;
Quit method 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deprecated Call auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a deprecated call&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.deprecatedCall.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureDeprecatedCall()&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception Button ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Trigger an SQLException&amp;lt;/code&amp;gt; ist im Export vorhanden, enthält aber noch keinen fertigen Demo-Code. Quelle: &amp;lt;code&amp;gt;FSY_Demo.sqlException.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Code need&#039;s to be written&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Dokumentation der SQL-Erfassung siehe [[#Events erfassen|03 Events erfassen]].&lt;br /&gt;
&lt;br /&gt;
== API Reference ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite dokumentiert die produktiv relevanten Methoden von &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== OSentryHL ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ist die empfohlene Klasse für Applikationscode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$init(pDSN)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Initialisiert das interne &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;-Objekt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Init of the main sentry object&lt;br /&gt;
Do iOSentry.$init(pDSN)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureMessage(pMessage)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet eine einfache Info-Message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures an Info Message&lt;br /&gt;
Do iOSentry.$captureException(pMessage,3,,&#039;info&#039;,kFalse,,kFalse) Returns code&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureException(pErrorText,pErrorCode,pExcType,pLevel)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet eine generische Exception.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture a generic Exception&lt;br /&gt;
#Add any custom tags / extras&lt;br /&gt;
Do $cinst.$addTag(&#039;Custom Test Tag&#039;,&#039;Euromnis&#039;)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureAnything(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet ein frei konfigurierbares Event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Capture a generic Sentry Report (max configurability)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hinweis: Der Parameter ist im Export als &amp;lt;code&amp;gt;pStacktraveInterface&amp;lt;/code&amp;gt; geschrieben.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureLog(pErrorText)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sendet ein Log-Event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Captures a Log Sentry Report&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;Log&#039;,&#039;warning&#039;,1,0,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureDeprecatedCall()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Meldet die Ausführung eines veralteten Codepfads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureSQLException(pErrorText,pStat)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Meldet einen SQL-Fehler mit SQL-Text und nativer Datenbankfehlermeldung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addTag(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt einen Tag für das nächste Event hinzu.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add a Tag to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addTag(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addExtra(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt ein Extra für das nächste Event hinzu.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Add an Extra to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addExtra(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setStatus(pStatus)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Aktiviert oder deaktiviert Sentry.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Toggels Sentry on or off&lt;br /&gt;
Do iOSentry.$setStatus(pStatus)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setUser()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt im Export feste [[#Demo Library|Demo]]-Userdaten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Set the User which should be linked to the Sentry Issue&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte diese Methode parametrisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== OSentry ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; ist die Low-Level-Klasse für Payload-Erzeugung und Versand.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$init(pDSN)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parst die DSN in Protokoll, Public Key, Host und Project ID.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraceInterface,pUserInterface,pExceptionInterface)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt JSON, sendet es an Sentry und behandelt Fehlerfälle.&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Default !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; ||  || Message&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; ||  || Fehlercode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExcType&amp;lt;/code&amp;gt; ||  || Exception-Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pLevel&amp;lt;/code&amp;gt; ||  || &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pStacktraceInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || [[#Stacktrace und Kontext|Stacktrace]] senden&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pUserInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || [[#Tags, Extras und User-Kontext|User-Kontext]] senden&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExceptionInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || Exception Interface senden&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateJson(...)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den Sentry JSON Payload als Binary.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateStacktraceInterface(pCulprit)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den Omnis-[[#Stacktrace und Kontext|Stacktrace]] inklusive Variablen und Kontextzeilen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateExceptionInterface(pType,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt das Sentry Exception Interface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Generate Row to store in the JSON&lt;br /&gt;
Do exceptionRow.$define(type,value,stacktrace)&lt;br /&gt;
Calculate exceptionRow.type as pType&lt;br /&gt;
Calculate exceptionRow.value as pValue&lt;br /&gt;
Calculate exceptionRow.stacktrace as &#039;sentry.interfaces.stacktrace&#039; ## Tells the exception interface that a stacktrace is passed aswell&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateUserInterface()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt den [[#Tags, Extras und User-Kontext|User-Kontext]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addTag(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt einen Tag zur internen Tag-Liste hinzu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$addExtra(pName,pValue)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Fügt ein Extra zur internen Extra-Liste hinzu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$clearList()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Leert [[#Tags, Extras und User-Kontext|Tags und Extras]] nach einem Request.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setUserData(pID,pName,pEmail)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt Userdaten für den nächsten Request.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setProxy(pProxyHost,pProxyPort)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt Proxy-Informationen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$setStatus(pStatus)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Setzt den Sentry-Status.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Toggels Sentry Reports on or off&lt;br /&gt;
Calculate iStatus as pStatus&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$writeJSON(pJSON,pBuffer)&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Schreibt fehlgeschlagene Reports lokal in eine Datei.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$getUnixTimestamp()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Gibt den aktuellen UNIX Timestamp zurück.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;$generateUUID()&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Erzeugt eine UUID für die Sentry Event ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Genereates a UUID for the issue id&lt;br /&gt;
Quit method OW3.$makeuuid(kFalse)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Es erscheinen keine Events in Sentry ===&lt;br /&gt;
&lt;br /&gt;
Prüfe zuerst, ob Sentry aktiv ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$setStatus(1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; beendet sich sofort, wenn der Status &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; oder leer ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Check if Sentry is enabled&lt;br /&gt;
If iStatus=0|isclear(iStatus)&lt;br /&gt;
	Quit method 0&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Die DSN ist falsch ===&lt;br /&gt;
&lt;br /&gt;
Prüfe, ob die DSN korrekt aus Sentry kopiert wurde. &amp;lt;code&amp;gt;OSentry.$init&amp;lt;/code&amp;gt; erwartet eine DSN, aus der Public Key, Host und Project ID gelesen werden können.&lt;br /&gt;
&lt;br /&gt;
Nach dem Setzen der DSN sollten in der [[#Demo Library|Demo-Library]] folgende Felder gefüllt sein:&lt;br /&gt;
&lt;br /&gt;
* Host&lt;br /&gt;
* Public Key&lt;br /&gt;
* Project ID&lt;br /&gt;
&lt;br /&gt;
=== Netzwerk oder Proxy blockiert den Request ===&lt;br /&gt;
&lt;br /&gt;
Wenn die Anwendung keinen direkten Zugriff auf Sentry hat, setze einen Proxy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.iOSentry.$setProxy(&#039;proxy.example.local&#039;,&#039;8080&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Intern wird der Proxy vor dem HTTP Request gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
If not(isclear(iProxyHost))&amp;amp;not(isclear(iProxyPort))&lt;br /&gt;
	HTTPSetProxyServer (iProxyHost,iProxyPort)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Report wird lokal gespeichert ===&lt;br /&gt;
&lt;br /&gt;
Wenn &amp;lt;code&amp;gt;HTTPPost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HTTPSend&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;HTTPRead&amp;lt;/code&amp;gt; fehlschlägt, speichert OSentry den Report lokal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Calculate path as sys(115)&lt;br /&gt;
Calculate filename as con(&#039;Sentryreport_&#039;,$cinst.$getUnixTimestamp(),&#039;.json&#039;)&lt;br /&gt;
Do fOP.$createfile(con(path,filename)) Returns err&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Suche im Omnis-Installationsordner nach Dateien mit dem Namen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Sentryreport_&amp;lt;timestamp&amp;gt;.json&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sentry antwortet nicht mit 200 OK ===&lt;br /&gt;
&lt;br /&gt;
Wenn die HTTP-Antwort kein &amp;lt;code&amp;gt;200 OK&amp;lt;/code&amp;gt; enthält, wird der JSON Report ebenfalls lokal gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTPRead (Socket,Buffer) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0|not(pos(&#039;200 OK&#039;,Buffer))&lt;br /&gt;
	# JSON may be corrupted or contains errors -&amp;gt; save json and the buffer as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,Buffer)&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -3&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mögliche Ursachen:&lt;br /&gt;
&lt;br /&gt;
* falsche Project ID&lt;br /&gt;
* falscher Public Key&lt;br /&gt;
* ungültige DSN&lt;br /&gt;
* JSON Payload wird von Sentry abgelehnt&lt;br /&gt;
* Netzwerk-Gateway verändert den Request&lt;br /&gt;
&lt;br /&gt;
=== Tags oder Extras erscheinen beim falschen Event ===&lt;br /&gt;
&lt;br /&gt;
[[#Tags, Extras und User-Kontext|Tags und Extras]] werden für den nächsten Request gesammelt. Nach erfolgreichem Request werden sie gelöscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iTagList.$clear()&lt;br /&gt;
Do iExtraList.$clear()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn ein Request fehlschlägt, wird ebenfalls aufgeräumt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do $cinst.$clearList()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prüfe trotzdem, ob in eigenen Wrapper-Methoden Tags und Extras direkt vor dem passenden Capture-Aufruf gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== User-Kontext zeigt Demo-Daten ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL.$setUser&amp;lt;/code&amp;gt; verwendet im Export feste Testdaten:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte die Methode parametrisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(pUserID,pUserName,pUserEmail)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception Demo-Button funktioniert nicht ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Trigger an SQLException&amp;lt;/code&amp;gt; ist im Export noch nicht implementiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Code need&#039;s to be written&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die produktive Methode für SQL-Fehler ist aber vorhanden. Siehe auch [[#Events erfassen|Events erfassen]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Do tSentry.$captureSQLException(&#039;SQL statement failed&#039;,stat)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Zu viele Events ===&lt;br /&gt;
&lt;br /&gt;
Sentry kann sehr schnell viele Events sammeln. Verwende für produktive Systeme:&lt;br /&gt;
&lt;br /&gt;
* klare Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
* sinnvolle Levels&lt;br /&gt;
* gezielte [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* keine Events in sehr häufigen Schleifen&lt;br /&gt;
* keine rein informativen Debug-Events ohne Nutzen&lt;br /&gt;
&lt;br /&gt;
=== Sensible Daten ===&lt;br /&gt;
&lt;br /&gt;
[[#Stacktrace und Kontext|Stacktrace]], Parameter, Instance Variablen, SQL-Text und [[#Tags, Extras und User-Kontext|Extras]] können sensible Daten enthalten. Prüfe vor produktiver Nutzung:&lt;br /&gt;
&lt;br /&gt;
* Welche Variablen werden übertragen?&lt;br /&gt;
* Enthalten SQL-Statements personenbezogene Daten?&lt;br /&gt;
* Werden Tokens oder Passwörter in Extras geschrieben?&lt;br /&gt;
* Sollen bestimmte Werte maskiert werden?&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Sentry&amp;diff=9526</id>
		<title>Sentry</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Sentry&amp;diff=9526"/>
		<updated>2026-06-12T13:59:28Z</updated>

		<summary type="html">&lt;p&gt;Silvan: Die Seite wurde neu angelegt: „&amp;lt;!-- MediaWiki source for page: Sentry --&amp;gt; &amp;lt;!-- Upload required files before publishing: sentry-issue.png, sentry-stack.png, sentry-tags.png, sentry-projects.png, demo-window.svg, demo-dsn.svg --&amp;gt; __TOC__  == Überblick ==  OSentry ist ein REST-API-Konnektor von Omnis Studio zu Sentry. Der Konnektor sendet Fehler, Messages, Logs und Laufzeitkontext aus Omnis-Anwendungen an Sentry, damit Probleme in produktiven Systemen sichtbar, gruppierbar und analysierb…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- MediaWiki source for page: Sentry --&amp;gt;&lt;br /&gt;
&amp;lt;!-- Upload required files before publishing: sentry-issue.png, sentry-stack.png, sentry-tags.png, sentry-projects.png, demo-window.svg, demo-dsn.svg --&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Überblick ==&lt;br /&gt;
&lt;br /&gt;
OSentry ist ein REST-API-Konnektor von Omnis Studio zu Sentry. Der Konnektor sendet Fehler, Messages, Logs und Laufzeitkontext aus Omnis-Anwendungen an Sentry, damit Probleme in produktiven Systemen sichtbar, gruppierbar und analysierbar werden.&lt;br /&gt;
&lt;br /&gt;
Diese Dokumentation beschreibt die [[#Installation|Installation]], die Nutzung in bestehenden Omnis-Anwendungen, die Definition eigener standardisierter Exception-Typen, die interne Struktur und die [[#Demo Library|Demo-Library]].&lt;br /&gt;
&lt;br /&gt;
=== Inhalt ===&lt;br /&gt;
&lt;br /&gt;
* [[#Installation|01 Installation]]&lt;br /&gt;
* [[#Quickstart|02 Quickstart]]&lt;br /&gt;
* [[#Events erfassen|03 Events erfassen]]&lt;br /&gt;
* [[#Eigene Exceptions standardisieren|04 Eigene Exceptions standardisieren]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|05 Tags Extras und User]]&lt;br /&gt;
* [[#Stacktrace und Kontext|06 Stacktrace und Kontext]]&lt;br /&gt;
* [[#Interne Architektur|07 Interne Architektur]]&lt;br /&gt;
* [[#Demo Library|08 Demo Library]]&lt;br /&gt;
* [[#API Reference|09 API Reference]]&lt;br /&gt;
* [[#Troubleshooting|10 Troubleshooting]]&lt;br /&gt;
&lt;br /&gt;
=== Kernidee ===&lt;br /&gt;
&lt;br /&gt;
OSentry besteht aus zwei produktiv relevanten Klassen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;: High-Level-Adapter für die Anwendung. Diese Klasse sollte von normalem Applikationscode aufgerufen werden.&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;: Low-Level-Adapter für DSN-Parsing, JSON-Erzeugung, [[#Stacktrace und Kontext|Stacktrace]]-Aufbereitung und HTTP-Kommunikation mit Sentry.&lt;br /&gt;
&lt;br /&gt;
Die Anwendung arbeitet im Normalfall mit &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;. Dadurch bleiben Sentry-spezifische Details zentral gekapselt und neue standardisierte Exception-Typen können als eigene Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Hauptfeatures ===&lt;br /&gt;
&lt;br /&gt;
* Direkte Anbindung von Omnis Studio an Sentry über REST API und DSN&lt;br /&gt;
* Erfassen von Exceptions, Messages, Logs und SQL-Fehlern&lt;br /&gt;
* Unterstützung der Sentry-Level &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
* Automatische Omnis-Kontextinformationen&lt;br /&gt;
* Omnis-[[#Stacktrace und Kontext|Stacktrace]] mit Klassen, Methoden, Zeilen und Variablen&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]] für Filterung und Gruppierung&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]] für zusätzliche Diagnoseinformationen&lt;br /&gt;
* Optionaler [[#Tags, Extras und User-Kontext|User-Kontext]]&lt;br /&gt;
* Proxy-Unterstützung&lt;br /&gt;
* Aktivieren und Deaktivieren der Sentry-Übertragung&lt;br /&gt;
* Lokales Speichern von Reports bei Übertragungsfehlern&lt;br /&gt;
&lt;br /&gt;
=== Screenshots ===&lt;br /&gt;
&lt;br /&gt;
[[Datei:sentry-issue.png|thumb|Sentry Issue-Übersicht]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:sentry-stack.png|thumb|Sentry Stacktrace mit Omnis-Kontext]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:sentry-tags.png|thumb|Sentry Tags und User-Kontext]]&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite beschreibt, wie OSentry in eine bestehende Omnis-Anwendung integriert wird.&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
* Omnis Studio Anwendung&lt;br /&gt;
* Sentry Account oder self-hosted Sentry Installation&lt;br /&gt;
* Ein Sentry-Projekt mit SDK-Typ &amp;lt;code&amp;gt;Other&amp;lt;/code&amp;gt;&lt;br /&gt;
* Die DSN des Sentry-Projekts&lt;br /&gt;
* Netzwerkzugriff auf Sentry&lt;br /&gt;
&lt;br /&gt;
Die exportierte [[#Demo Library|Demo-Library]] wurde mit Omnis &amp;lt;code&amp;gt;11.1&amp;lt;/code&amp;gt; erstellt.&lt;br /&gt;
&lt;br /&gt;
=== Sentry-Projekt erstellen ===&lt;br /&gt;
&lt;br /&gt;
# In Sentry ein neues Projekt erstellen.&lt;br /&gt;
# Als SDK &amp;lt;code&amp;gt;Other&amp;lt;/code&amp;gt; auswählen.&lt;br /&gt;
# Die DSN des Projekts kopieren.&lt;br /&gt;
&lt;br /&gt;
Die DSN wird beim Initialisieren verwendet. &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; zerlegt sie intern in Public Key, Host und Project ID.&lt;br /&gt;
&lt;br /&gt;
=== Klassen kopieren ===&lt;br /&gt;
&lt;br /&gt;
Kopiere die folgenden Klassen in deine bestehende Omnis-Library:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Demo-spezifischen Klassen sind für die produktive Integration nicht erforderlich. Damit sind die übrigen Klassen der Demo-Library gemeint, zum Beispiel &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt;. Diese Klassen dienen nur dazu, die [[#Demo Library|Demo-Library]] mit Fenster, SQLite-Testdaten und Beispielaufrufen auszuführen.&lt;br /&gt;
&lt;br /&gt;
=== Task Variable anlegen ===&lt;br /&gt;
&lt;br /&gt;
Lege in deiner Startup Task eine Task Variable an:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Name !! Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; sollte als global erreichbarer Singleton der Anwendung verwendet werden. In Omnis ist dafür eine Task Variable sinnvoll, weil sie von Fenstern, Objektklassen und zentralen Error-Handlern aus konsistent erreichbar ist. Dadurch gibt es genau eine aktive Sentry-Konfiguration mit einer DSN, einem Status, optionalen Proxy-Daten und gemeinsamen Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Im [[#Demo Library|Demo-Projekt]] ist diese Variable in &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; definiert.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung im Startup Task ===&lt;br /&gt;
&lt;br /&gt;
Initialisiere &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; beim Start deiner Anwendung mit der DSN deines Sentry-Projekts:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;&amp;lt;DSN&amp;gt;&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die [[#Demo Library|Demo-Library]] ruft im Startup Task ebenfalls die Initialisierung auf. Quelle: &amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Init Sentry on lbs startup&lt;br /&gt;
Do tSentry.$init()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In einer produktiven Anwendung sollte die DSN explizit oder aus einer Konfiguration übergeben werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;https://PUBLIC_KEY@sentry.io/PROJECT_ID&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Systeme ist es sinnvoll, die DSN nicht fest im Code zu hinterlegen. Speichere sie besser in einer Datenbank, einer Konfigurationstabelle oder einem Config File. Dadurch kann die DSN pro Kunde, Umgebung oder Installation geändert werden, ohne die Library neu auszuliefern.&lt;br /&gt;
&lt;br /&gt;
=== Testcall ===&lt;br /&gt;
&lt;br /&gt;
Nach der Initialisierung kann ein erstes Testevent gesendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello World!&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles korrekt eingerichtet ist, erscheint das Event im Sentry-Projekt.&lt;br /&gt;
&lt;br /&gt;
=== Proxy konfigurieren ===&lt;br /&gt;
&lt;br /&gt;
Falls die Anwendung in einem geschützten Netzwerk läuft, kann ein Proxy gesetzt werden. Die Methode befindet sich im Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.iOSentry.$setProxy(&#039;proxy.example.local&#039;,&#039;8080&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die interne Implementierung setzt den Proxy vor dem HTTP-Request:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Configure proxy; needed when sending data out of secured networks&lt;br /&gt;
If not(isclear(iProxyHost))&amp;amp;not(isclear(iProxyPort))&lt;br /&gt;
	HTTPSetProxyServer (iProxyHost,iProxyPort)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sentry aktivieren oder deaktivieren ===&lt;br /&gt;
&lt;br /&gt;
OSentry kann zentral ein- oder ausgeschaltet werden. Es ist empfohlen, Sentry in der Entwicklungs-Version standardmäßig zu deaktivieren oder eine separate Entwicklungs-DSN zu verwenden. So landen lokale Tests, Debug-Fehler und absichtlich ausgelöste Exceptions nicht im produktiven Sentry-Projekt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$setStatus(1)     ## aktiv&lt;br /&gt;
Do tSentry.$setStatus(0)     ## inaktiv&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; wird vor dem Senden geprüft:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Check if Sentry is enabled&lt;br /&gt;
If iStatus=0|isclear(iStatus)&lt;br /&gt;
	Quit method 0&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite zeigt die minimale Integration in eine bestehende Omnis-Anwendung.&lt;br /&gt;
&lt;br /&gt;
=== 1. Klassen übernehmen ===&lt;br /&gt;
&lt;br /&gt;
Kopiere &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; in deine Library.&lt;br /&gt;
&lt;br /&gt;
=== 2. Task Variable erstellen ===&lt;br /&gt;
&lt;br /&gt;
In der Startup Task:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Name !! Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tSentry&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== 3. Sentry initialisieren ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$init(&#039;https://PUBLIC_KEY@sentry.io/PROJECT_ID&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL.$init&amp;lt;/code&amp;gt; delegiert an das Low-Level-Objekt &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Init of the main sentry object&lt;br /&gt;
Do iOSentry.$init(pDSN)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 4. Message senden ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die [[#Demo Library|Demo-Library]] verwendet genau diesen Aufruf im Button &amp;lt;code&amp;gt;Trigger a message&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.message.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 5. Exception senden ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6. In Sentry prüfen ===&lt;br /&gt;
&lt;br /&gt;
In Sentry sollte anschließend ein neues Event sichtbar sein. Je nach Event-Typ enthält es:&lt;br /&gt;
&lt;br /&gt;
* Message&lt;br /&gt;
* Level&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|User-Kontext]]&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]]&lt;br /&gt;
* Omnis-Kontextinformationen&lt;br /&gt;
&lt;br /&gt;
== Events erfassen ==&lt;br /&gt;
&lt;br /&gt;
OSentryHL ist die empfohlene Einstiegsschicht für Applikationscode. Die Klasse bietet sprechende Methoden für typische Event-Arten und ruft intern &amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
&lt;br /&gt;
=== Message ===&lt;br /&gt;
&lt;br /&gt;
Eine einfache Information wird mit &amp;lt;code&amp;gt;$captureMessage&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$captureMessage(&#039;Hello World!&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Captures an Info Message&lt;br /&gt;
Do iOSentry.$captureException(pMessage,3,,&#039;info&#039;,kFalse,,kFalse) Returns code&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Level: &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;&lt;br /&gt;
* Kein [[#Stacktrace und Kontext|Stacktrace]]&lt;br /&gt;
* Kein [[#Tags, Extras und User-Kontext|User Interface]]&lt;br /&gt;
* Geeignet für einfache Statusmeldungen oder technische Hinweise&lt;br /&gt;
&lt;br /&gt;
=== Log ===&lt;br /&gt;
&lt;br /&gt;
Ein Log-Event wird mit &amp;lt;code&amp;gt;$captureLog&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$captureLog(&#039;Uh oh this is a Log because something went wrong&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Captures a Log Sentry Report&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;Log&#039;,&#039;warning&#039;,1,0,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Level: &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]] aktiv&lt;br /&gt;
* Exception Interface in diesem Wrapper deaktiviert&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|User Interface]] aktiv&lt;br /&gt;
&lt;br /&gt;
=== Generische Exception ===&lt;br /&gt;
&lt;br /&gt;
Eine generische Exception wird mit &amp;lt;code&amp;gt;$captureException&amp;lt;/code&amp;gt; gesendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Method to capture a generic Exception&lt;br /&gt;
#Add any custom tags / extras&lt;br /&gt;
Do $cinst.$addTag(&#039;Custom Test Tag&#039;,&#039;Euromnis&#039;)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; || Text, der in Sentry als Message sichtbar ist&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; || Fehlercode oder fachlicher Code&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExcType&amp;lt;/code&amp;gt; || Exception-Typ für Benennung und Gruppierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pLevel&amp;lt;/code&amp;gt; || Sentry-Level&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Gültige Levels:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception ===&lt;br /&gt;
&lt;br /&gt;
SQL-Fehler können mit &amp;lt;code&amp;gt;$captureSQLException&amp;lt;/code&amp;gt; gemeldet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$captureSQLException(&#039;SQL statement failed&#039;,stat)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verhalten:&lt;br /&gt;
&lt;br /&gt;
* Fügt die Datenbank als [[#Tags, Extras und User-Kontext|Tag]] hinzu&lt;br /&gt;
* Fügt SQL-Text als [[#Tags, Extras und User-Kontext|Extra]] hinzu&lt;br /&gt;
* Fügt native Datenbankfehlermeldung als [[#Tags, Extras und User-Kontext|Extra]] hinzu&lt;br /&gt;
* Sendet das Event als &amp;lt;code&amp;gt;SQL-Exception&amp;lt;/code&amp;gt; mit Level &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deprecated Call ===&lt;br /&gt;
&lt;br /&gt;
Veraltete Codepfade können gezielt gemeldet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$captureDeprecatedCall()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Wrapper eignet sich, um zu erkennen, ob alter Code in produktiven Systemen noch ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
=== Frei konfigurierbares Event ===&lt;br /&gt;
&lt;br /&gt;
Für Sonderfälle gibt es &amp;lt;code&amp;gt;$captureAnything&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$captureAnything(&#039;Text&#039;,1001,&#039;Custom Type&#039;,&#039;error&#039;,kTrue,kTrue,kTrue)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementierung in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Capture a generic Sentry Report (max configurability)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Methode bietet maximale Flexibilität. Für wiederkehrende Exception-Typen sollte aber eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; angelegt werden. Siehe [[#Eigene Exceptions standardisieren|04 Eigene Exceptions standardisieren]].&lt;br /&gt;
&lt;br /&gt;
== Eigene Exceptions standardisieren ==&lt;br /&gt;
&lt;br /&gt;
Wenn ein Exception-Typ mehrfach in der Anwendung vorkommt, sollte er nicht überall manuell mit &amp;lt;code&amp;gt;$captureException&amp;lt;/code&amp;gt; aufgebaut werden. Besser ist eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dadurch entsteht eine zentrale, wiederverwendbare Definition für:&lt;br /&gt;
&lt;br /&gt;
* Exception-Typ&lt;br /&gt;
* Sentry-Level&lt;br /&gt;
* Fehlercode&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]]&lt;br /&gt;
* [[#Stacktrace und Kontext|Stacktrace]]/[[#Tags, Extras und User-Kontext|User]]/Exception Interface&lt;br /&gt;
&lt;br /&gt;
Die automatisch gesetzten [[#Tags, Extras und User-Kontext|Tags und Extras]] aus &amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; müssen in solchen Wrappern nicht erneut ergänzt werden. Eigene Exception-Methoden setzen nur zusätzliche Werte, die für diesen standardisierten Exception-Typ relevant sind.&lt;br /&gt;
&lt;br /&gt;
=== Warum über OSentryHL? ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ist die Abstraktionsschicht für Applikationscode. Sie kapselt die Details von &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und sorgt dafür, dass Aufrufe in der Anwendung kurz und konsistent bleiben.&lt;br /&gt;
&lt;br /&gt;
Bestehende Beispiele aus &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Empfohlenes Muster ===&lt;br /&gt;
&lt;br /&gt;
Für jeden standardisierten Exception-Typ wird eine eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; erstellt.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Captures a validation exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Field&#039;,pField)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Invalid Value&#039;,pValue)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,2001,&#039;Validation-Exception&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mögliche Parameter der neuen Methode:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Beispiel !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;Invalid customer number&#039;&amp;lt;/code&amp;gt; || Sentry Message&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pModule&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;Customer&#039;&amp;lt;/code&amp;gt; || Filterbarer Tag&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pField&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;cu_number&#039;&amp;lt;/code&amp;gt; || Diagnoseinformation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pValue&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&#039;ABC&#039;&amp;lt;/code&amp;gt; || Diagnoseinformation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der Applikationscode bleibt dadurch einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$captureValidationException(&#039;Invalid customer number&#039;,&#039;Customer&#039;,&#039;cu_number&#039;,cu_number)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel: Business Rule Exception ===&lt;br /&gt;
&lt;br /&gt;
Neue Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Captures a business rule violation&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addTag(&#039;Business Rule&#039;,pRuleName)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Details&#039;,pDetails)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aufruf in der Anwendung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$captureBusinessRuleViolation(&#039;Invoice cannot be posted&#039;,&#039;Invoice&#039;,&#039;PostingAllowed&#039;,&#039;Invoice is missing customer&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel: Integration Exception ===&lt;br /&gt;
&lt;br /&gt;
Neue Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Captures an integration exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Integration&#039;,pSystem)&lt;br /&gt;
Do $cinst.$addTag(&#039;Endpoint&#039;,pEndpoint)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Payload&#039;,pPayload)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Response&#039;,pResponse)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,4001,&#039;Integration-Exception&#039;,&#039;error&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method code&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aufruf in der Anwendung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$captureIntegrationException(&#039;External API request failed&#039;,&#039;ERP&#039;,&#039;/api/customer&#039;,jsonPayload,responseText)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Namenskonventionen ===&lt;br /&gt;
&lt;br /&gt;
Empfehlung für neue Methoden:&lt;br /&gt;
&lt;br /&gt;
* Methodenname beginnt mit &amp;lt;code&amp;gt;$capture&amp;lt;/code&amp;gt;&lt;br /&gt;
* Der fachliche Typ steht im Methodennamen&lt;br /&gt;
* Der Sentry Exception Type ist stabil und ändert sich nicht laufend&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Tags]] sind kurz und filterbar&lt;br /&gt;
* [[#Tags, Extras und User-Kontext|Extras]] dürfen länger sein und Diagnoseinformationen enthalten&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureValidationException&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureBusinessRuleViolation&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureIntegrationException&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$capturePermissionViolation&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;$captureConfigurationError&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error Codes ===&lt;br /&gt;
&lt;br /&gt;
Verwende feste Fehlercodes für standardisierte Exception-Typen. Dadurch können Events in Sentry besser gefiltert und wiedererkannt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Code !! Exception Type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Validation-Exception&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Business-Rule-Violation&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Integration-Exception&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;5001&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Configuration-Error&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Wann nicht standardisieren? ===&lt;br /&gt;
&lt;br /&gt;
Nicht jeder Einzelfall braucht eine eigene Methode. Für einmalige technische Tests oder sehr spezielle Fälle reicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald ein Exception-Typ aber mehrfach vorkommt oder fachlich relevant ist, sollte er als eigene Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
== Tags, Extras und User-Kontext ==&lt;br /&gt;
&lt;br /&gt;
Tags, Extras und User-Kontext reichern Sentry-Events mit zusätzlichen Informationen an. Diese Informationen helfen beim Filtern, Gruppieren und Analysieren.&lt;br /&gt;
&lt;br /&gt;
=== Tags ===&lt;br /&gt;
&lt;br /&gt;
Tags sind kurze, filterbare Werte.&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* Datenbank&lt;br /&gt;
* Kunde&lt;br /&gt;
* Modul&lt;br /&gt;
* Umgebung&lt;br /&gt;
* Error Code&lt;br /&gt;
* Omnis-Version&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Add a Tag to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addTag(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Adds a tag to the next request processed&lt;br /&gt;
Do iTagList.$add(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$addTag(&#039;Module&#039;,&#039;Invoice&#039;)&lt;br /&gt;
Do tSentry.$addTag(&#039;Customer&#039;,&#039;10001&#039;)&lt;br /&gt;
Do tSentry.$captureException(&#039;Invoice posting failed&#039;,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Extras ===&lt;br /&gt;
&lt;br /&gt;
Extras sind Detailinformationen, die nicht primär zum Filtern gedacht sind.&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* SQL-Text&lt;br /&gt;
* Native Datenbankfehlermeldung&lt;br /&gt;
* Payload&lt;br /&gt;
* Response Body&lt;br /&gt;
* interne IDs&lt;br /&gt;
* zusätzliche Debug-Informationen&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Add an Extra to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addExtra(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Methode in &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Adds extra information to the next request being processed&lt;br /&gt;
Do iExtraList.$add(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel aus der SQL Exception:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Automatische Tags ===&lt;br /&gt;
&lt;br /&gt;
Die folgenden Tags werden bei jedem Event automatisch von &amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; ergänzt. Sie müssen bei eigenen Exceptions nicht erneut gesetzt werden. Eigene Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; sollten nur zusätzliche, fachlich oder technisch relevante Tags hinzufügen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; fügt mehrere Tags automatisch hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Add static tags&lt;br /&gt;
Do iTagList.$add(&#039;Omnisversion&#039;,sys(1))&lt;br /&gt;
Calculate systemversionRow as systemversion()&lt;br /&gt;
Do iTagList.$add(&#039;Plattform&#039;,con(sys(8),pick(systemversionRow.server,&#039;&#039;,&#039; SRV&#039;)))&lt;br /&gt;
Do iTagList.$add(&#039;OS Version&#039;,con(systemversionRow.major,&#039;.&#039;,systemversionRow.minor,&#039;.&#039;,systemversionRow.build))&lt;br /&gt;
Do iTagList.$add(&#039;error_code&#039;,pErrorCode)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Automatisch gesendete Tags:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tag !! Herkunft !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Omnisversion&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;sys(1)&amp;lt;/code&amp;gt; || Zeigt, mit welcher Omnis-Version das Event erzeugt wurde&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Plattform&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;sys(8)&amp;lt;/code&amp;gt; und Server-Flag aus &amp;lt;code&amp;gt;systemversion()&amp;lt;/code&amp;gt; || Unterscheidet Plattform und Server Runtime&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OS Version&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;systemversionRow.major/minor/build&amp;lt;/code&amp;gt; || Zeigt die Betriebssystemversion&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;error_code&amp;lt;/code&amp;gt; || Parameter &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; || Verbindet das Event mit dem übergebenen Fehlercode&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Beispiel für eine eigene Exception: Der Wrapper muss nicht erneut &amp;lt;code&amp;gt;Omnisversion&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;OS Version&amp;lt;/code&amp;gt; setzen. Er ergänzt nur das, was für diesen Exception-Typ zusätzlich hilfreich ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do $cinst.$addTag(&#039;Module&#039;,pModule)&lt;br /&gt;
Do $cinst.$addTag(&#039;Business Rule&#039;,pRuleName)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,3001,&#039;Business-Rule-Violation&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Automatische Extras ===&lt;br /&gt;
&lt;br /&gt;
Auch die folgenden Extras werden bei jedem Event automatisch ergänzt. Bei eigenen Exceptions müssen nur zusätzliche Extras gesetzt werden, zum Beispiel ein SQL-Statement, ein Payload oder fachliche Zusatzdaten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; fügt offene Fenster, offene Reports und die aktuelle Printfile hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Static extra 1: All open windows&lt;br /&gt;
Do $root.$iwindows.$makelist($ref.$name) Returns nameList&lt;br /&gt;
For i from 1 to nameList.$linecount step 1&lt;br /&gt;
	Calculate windows as con(windows,&#039;, &#039;,nameList.[i].1)&lt;br /&gt;
End For&lt;br /&gt;
Calculate windows as right(windows,len(windows)-2)&lt;br /&gt;
Do iExtraList.$add(&#039;Open Windows&#039;,windows)&lt;br /&gt;
&lt;br /&gt;
# Static extra 2: All open reports&lt;br /&gt;
Do $root.$ireports.$makelist($ref.$name) Returns nameList&lt;br /&gt;
For i from 1 to nameList.$linecount step 1&lt;br /&gt;
	Calculate reports as con(reports,&#039;, &#039;,nameList.[i].1)&lt;br /&gt;
End For&lt;br /&gt;
Calculate reports as right(reports,len(reports)-2)&lt;br /&gt;
Do iExtraList.$add(&#039;Open Reports&#039;,reports)&lt;br /&gt;
Do iExtraList.$add(&#039;Current Printfile&#039;,$root.$prefs.$printfile)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Automatisch gesendete Extras:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Extra !! Herkunft !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Open Windows&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$iwindows.$makelist($ref.$name)&amp;lt;/code&amp;gt; || Zeigt, welche Fenster im Moment des Events offen waren&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Open Reports&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$ireports.$makelist($ref.$name)&amp;lt;/code&amp;gt; || Zeigt, welche Reports im Moment des Events offen waren&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Current Printfile&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;$root.$prefs.$printfile&amp;lt;/code&amp;gt; || Zeigt die aktuell gesetzte Printfile&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Beispiel für zusätzliche Extras in einem eigenen Wrapper:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do $cinst.$addExtra(&#039;Payload&#039;,pPayload)&lt;br /&gt;
Do $cinst.$addExtra(&#039;Response&#039;,pResponse)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,4001,&#039;Integration-Exception&#039;,&#039;error&#039;,1,1,1) Returns code&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== User-Kontext ===&lt;br /&gt;
&lt;br /&gt;
Der User-Kontext ordnet ein Event einem betroffenen Benutzer zu. In Sentry erscheint dadurch ein eigener User-Bereich, und Events können nach Benutzer gefiltert oder gruppiert werden. Das ist besonders hilfreich, wenn ein Fehler nur bei einzelnen Kunden, Arbeitsplätzen oder Benutzerkonten auftritt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; unterstützt drei User-Felder:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feld !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt; || stabile interne Benutzer-ID oder Kundennummer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;username&amp;lt;/code&amp;gt; || lesbarer Benutzername&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;email&amp;lt;/code&amp;gt; || E-Mail-Adresse, falls sie übertragen werden darf&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der User-Kontext wird nur in das Event geschrieben, wenn das User Interface beim Capture-Aufruf aktiviert ist. Die Standardmethode &amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; hat &amp;lt;code&amp;gt;pUserInterface&amp;lt;/code&amp;gt; standardmäßig auf &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt;. Einzelne High-Level-Methoden können das bewusst deaktivieren, zum Beispiel &amp;lt;code&amp;gt;$captureMessage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; kann User-Daten an das Event anhängen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Sets userinformation for the next request being processed&lt;br /&gt;
Calculate iUserID as pID&lt;br /&gt;
Calculate iUserName as pName&lt;br /&gt;
Calculate iUserEmail as pEmail&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das User Interface wird so generiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Create user data row&lt;br /&gt;
Do UserdataRow.$define(id,email,username)&lt;br /&gt;
&lt;br /&gt;
Calculate UserdataRow.id as iUserID&lt;br /&gt;
Calculate UserdataRow.email as iUserEmail&lt;br /&gt;
Calculate UserdataRow.username as iUserName&lt;br /&gt;
&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;user&#039;,&#039;&#039;)&lt;br /&gt;
Do JSON.$setobject(&#039;user&#039;,UserdataRow)&lt;br /&gt;
&lt;br /&gt;
Calculate jsonString as OJSON.$formatjson(JSON.$getjson())&lt;br /&gt;
&lt;br /&gt;
Quit method jsonString&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die aktuelle Demo-Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; verwendet feste Testdaten. Quelle: &amp;lt;code&amp;gt;OSentryHL.$setUser&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Set the User which should be linked to the Sentry Issue&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte diese Methode angepasst und parametrisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(pUserID,pUserName,pUserEmail)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Empfohlen ist, den User nach Login oder beim Wechsel des aktiven Benutzers zentral zu setzen. Bei anonymen oder sensiblen Installationen kann statt Name und E-Mail auch nur eine interne ID oder ein pseudonymisierter Wert verwendet werden.&lt;br /&gt;
&lt;br /&gt;
=== Datenschutz ===&lt;br /&gt;
&lt;br /&gt;
Prüfe vor produktiver Nutzung, welche Daten an Sentry gesendet werden. Besonders kritisch sind:&lt;br /&gt;
&lt;br /&gt;
* personenbezogene Daten&lt;br /&gt;
* Kundendaten&lt;br /&gt;
* SQL-Statements mit Werten&lt;br /&gt;
* Zugangsdaten&lt;br /&gt;
* Tokens&lt;br /&gt;
* interne Pfade&lt;br /&gt;
&lt;br /&gt;
Tags und Extras sollten so gestaltet werden, dass sie für die Fehleranalyse hilfreich sind, aber keine unnötigen sensiblen Daten übertragen.&lt;br /&gt;
&lt;br /&gt;
== Stacktrace und Kontext ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; erzeugt einen Omnis-spezifischen Stacktrace und übergibt ihn an Sentry. Dadurch sieht man in Sentry nicht nur eine Fehlermeldung, sondern auch Klassen, Methoden, Zeilen und Variablenkontext. Ergänzende Informationen zu [[#Tags, Extras und User-Kontext|Tags, Extras und User-Kontext]] stehen auf der separaten Kontext-Seite.&lt;br /&gt;
&lt;br /&gt;
[[Datei:sentry-stack.png|thumb|Sentry Stacktrace mit Omnis-Kontext]]&lt;br /&gt;
&lt;br /&gt;
=== Stack lesen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateStacktraceInterface&amp;lt;/code&amp;gt; verwendet &amp;lt;code&amp;gt;sys(192)&amp;lt;/code&amp;gt;, um den aktuellen Omnis-Stack zu lesen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Clean up the Stacklist (remove OSentry classes from the stack)&lt;br /&gt;
Do sys(192) Returns sys192List&lt;br /&gt;
For sys192List.$line from 1 to sys192List.$linecount step 1&lt;br /&gt;
	Set reference class to sys192List.classitem&lt;br /&gt;
	If pos(&#039;OSentry&#039;,class.$name)&amp;gt;0|pos(&#039;OSentryHL&#039;,class.$name)&amp;gt;0&lt;br /&gt;
		Do sys192List.[sys192List.$line].$selected.$assign(kTrue)&lt;br /&gt;
	End If&lt;br /&gt;
End For&lt;br /&gt;
Do sys192List.$remove(kListDeleteSelected)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Interne Frames von &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; werden entfernt, damit in Sentry die fachlich relevanten Stellen sichtbar bleiben.&lt;br /&gt;
&lt;br /&gt;
=== SQL-Error Frames entfernen ===&lt;br /&gt;
&lt;br /&gt;
Bestimmte interne SQL-Fehlerframes werden ebenfalls entfernt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Remove some other classes which we do not want to display&lt;br /&gt;
If sys192List.1.method=&#039;$sqlerror&#039;&lt;br /&gt;
	Do sys192List.$remove(1)&lt;br /&gt;
Else If sys192List.1.method=&#039;$statementerror&#039;&lt;br /&gt;
	Do sys192List.$remove(1)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Frames erzeugen ===&lt;br /&gt;
&lt;br /&gt;
Für jeden Stack-Eintrag werden Funktion, Zeilennummer und Kontextzeile erzeugt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Loop through every item on the omnis stack&lt;br /&gt;
For sys192List.$line from 1 to sys192List.$linecount step 1&lt;br /&gt;
	Set reference class to sys192List.classitem&lt;br /&gt;
	Calculate className as class.$name&lt;br /&gt;
	&lt;br /&gt;
	# Create the content row&lt;br /&gt;
	Do contentRow.$define(vars,function,pre_context,context_line,lineno,filename,post_context)&lt;br /&gt;
	Calculate contentRow.lineno as sys192List.line&lt;br /&gt;
	Calculate contentRow.filename as testFileName&lt;br /&gt;
	Calculate contentRow.context_line as sys192List.linetext&lt;br /&gt;
	If isclear(sys192List.object)&lt;br /&gt;
		Calculate contentRow.function as con(className,&#039;.&#039;,sys192List.method) ## If it&#039;s a class method&lt;br /&gt;
	Else&lt;br /&gt;
		Calculate contentRow.function as con(className,&#039;.&#039;,sys192List.object,&#039;.&#039;,sys192List.method) ## If it&#039;s a method of an object of a class (e.g. Headedlist)&lt;br /&gt;
	End If&lt;br /&gt;
	Do contentList.$add(contentRow)&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablen aufnehmen ===&lt;br /&gt;
&lt;br /&gt;
Pro Stackframe werden Instance Variablen und Parameter gesammelt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Get all iVars&lt;br /&gt;
Do varList.$define(name,value)&lt;br /&gt;
Set reference class to sys192List.inst&lt;br /&gt;
Do $cinst.$getVars(&#039;ivars&#039;,class) Returns varList&lt;br /&gt;
&lt;br /&gt;
# Get all params&lt;br /&gt;
Calculate paramList as sys192List.params&lt;br /&gt;
For paramList.$line from 1 to paramList.$linecount step 1&lt;br /&gt;
	If not(paramList.value=&#039;(Not empty)&#039;)&lt;br /&gt;
		Do varList.$add(paramList.name,paramList.value)&lt;br /&gt;
	Else&lt;br /&gt;
		Do varList.$add(paramList.name,&#039;(Not empty)&#039;)&lt;br /&gt;
	End If&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pre- und Post-Context ===&lt;br /&gt;
&lt;br /&gt;
OSentry fügt Methodenzeilen vor und nach der aktuellen Zeile hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Pre Context (all method lines before the error occured)&lt;br /&gt;
Set reference method to sys192List.methoditem&lt;br /&gt;
Do precontextList.$define(line)&lt;br /&gt;
For i from 1 to sys192List.line-1 step 1&lt;br /&gt;
	Do precontextList.$add(method.$methodlines.[i].$text)&lt;br /&gt;
End For&lt;br /&gt;
&lt;br /&gt;
# Post Context (all method lines after the error occured&lt;br /&gt;
Do postcontextList.$define(line)&lt;br /&gt;
For i from sys192List.line+1 to method.$methodlines.$count step 1&lt;br /&gt;
	Do postcontextList.$add(method.$methodlines.[i].$text)&lt;br /&gt;
End For&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablentypen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$getVars&amp;lt;/code&amp;gt; unterstützt Basisvariablen, Rows und Lists.&lt;br /&gt;
&lt;br /&gt;
Basisvariablen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
If varType=&#039;char&#039;|varType=&#039;boolean&#039;|varType=&#039;integer&#039;|varType=&#039;number&#039;|varType=&#039;date&#039;&lt;br /&gt;
	Calculate varContent as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	Do varList.$add(varName,varContent)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Else If varType=&#039;row&#039;&lt;br /&gt;
	Calculate varRow as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	If varRow.$colcount=0&lt;br /&gt;
		Do varList.$add(varName,&#039;(Empty)&#039;)&lt;br /&gt;
	Else&lt;br /&gt;
		For Z2 from 1 to varRow.$colcount step 1&lt;br /&gt;
			Calculate varContent as con(varContent,varRow.$cols.[Z2].$name,&#039;: &#039;,varRow.[Z2],&#039;, &#039;)&lt;br /&gt;
		End For&lt;br /&gt;
		Do varList.$add(varName,varContent)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lists:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Else If varType=&#039;list&#039;&lt;br /&gt;
	Calculate varListType as pItemRef.$[pVarType].[varName]&lt;br /&gt;
	Calculate varContent as con(&#039;Colcount: &#039;,varListType.$colcount,&#039;, &#039;,&#039;Linecount: &#039;,varListType.$linecount,&#039;, &#039;,&#039;Current Line: &#039;,varListType.$line)&lt;br /&gt;
	If varListType.$linecount=0&amp;amp;varListType.$line=0&amp;amp;varListType.$colcount=0&lt;br /&gt;
		Do varList.$add(varName,&#039;(Empty)&#039;)&lt;br /&gt;
		Calculate varContent as &#039;&#039;&lt;br /&gt;
	Else&lt;br /&gt;
		For Z3 from 1 to varListType.$colcount step 1&lt;br /&gt;
			Calculate colName as varListType.$cols.[Z3].$name&lt;br /&gt;
			Calculate varContent as con(varContent,&#039;  &#039;,colName,&#039;: &#039;,varListType.[colName])&lt;br /&gt;
		End For&lt;br /&gt;
		Do varList.$add(varName,varContent)&lt;br /&gt;
		Calculate varContent as &#039;&#039;&lt;br /&gt;
	End If&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
&lt;br /&gt;
Stacktrace und Variablenkontext sind sehr hilfreich, können aber sensible Daten enthalten. Vor produktiver Nutzung sollte geprüft werden, ob bestimmte Variablen anonymisiert oder ausgeschlossen werden müssen.&lt;br /&gt;
&lt;br /&gt;
== Interne Architektur ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite beschreibt die produktiv relevanten Klassen &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Klassenübersicht ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Rolle&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; || High-Level-Adapter für Applikationscode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; || Low-Level-Adapter für JSON, [[#Stacktrace und Kontext|Stacktrace]] und HTTP&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Startup und Beispiel für Initialisierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-Code für [[#Stacktrace und Kontext|Stacktrace]]-Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; || [[#Demo Library|Demo]]-DB Initialisierung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt; || SQLite Session für [[#Demo Library|Demo]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Empfohlener Aufrufweg ===&lt;br /&gt;
&lt;br /&gt;
Applikationscode sollte &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; verwenden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; delegiert anschließend an &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ablauf eines Events ===&lt;br /&gt;
&lt;br /&gt;
# Applikationscode ruft Methode in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; fügt bei Bedarf [[#Tags, Extras und User-Kontext|Tags und Extras]] hinzu.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ruft &amp;lt;code&amp;gt;iOSentry.$captureException(...)&amp;lt;/code&amp;gt; auf.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; prüft, ob Sentry aktiv ist.&lt;br /&gt;
# &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; erzeugt JSON.&lt;br /&gt;
# [[#Stacktrace und Kontext|Stacktrace]], Exception Interface und [[#Tags, Extras und User-Kontext|User Interface]] werden optional ergänzt.&lt;br /&gt;
# HTTP Header und Sentry Auth Header werden erstellt.&lt;br /&gt;
# JSON wird per HTTPS an Sentry gesendet.&lt;br /&gt;
# Bei Erfolg werden [[#Tags, Extras und User-Kontext|Tags und Extras]] geleert.&lt;br /&gt;
# Bei Fehler wird der JSON Report lokal gespeichert.&lt;br /&gt;
&lt;br /&gt;
=== DSN Parsing ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$init&amp;lt;/code&amp;gt; zerlegt die DSN:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Parse the DSN into Public Key, Host and Project ID&lt;br /&gt;
If len(pDSN)&amp;gt;5&lt;br /&gt;
	Calculate iDSN as pDSN&lt;br /&gt;
	Calculate part1 as strtok(&#039;iDSN&#039;,&#039;@&#039;)&lt;br /&gt;
	Calculate iProtocol as strtok(&#039;part1&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iProtocol as left(iProtocol,len(iProtocol)-1)&lt;br /&gt;
	Do strtok(&#039;part1&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iPubKey as strtok(&#039;part1&#039;,&#039;:&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Calculate iHost as strtok(&#039;iDSN&#039;,&#039;/&#039;)&lt;br /&gt;
	Calculate iProID as iDSN&lt;br /&gt;
	&lt;br /&gt;
	#Save the values for the next startup&lt;br /&gt;
	Calculate $cclass.$ivardefs.iPubKey.$objinitval as con(&#039;&amp;quot;&#039;,iPubKey,&#039;&amp;quot;&#039;)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iHost.$objinitval as con(&#039;&amp;quot;&#039;,iHost,&#039;&amp;quot;&#039;)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iProID.$objinitval as con(&#039;&amp;quot;&#039;,iProID,&#039;&amp;quot;&#039;)&lt;br /&gt;
End If&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== JSON-Erzeugung ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$generateJson&amp;lt;/code&amp;gt; ist die zentrale Methode für den Payload. Sie setzt unter anderem:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;event_id&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;logger&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;platform&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;culprit&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;timestamp&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sdk&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;message&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;level&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;tags&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;extra&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;exception&amp;lt;/code&amp;gt;&lt;br /&gt;
* optional &amp;lt;code&amp;gt;stacktrace&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auszug:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Add all required fields (those are required from the API)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;event_id&#039;,$cinst.$generateUUID()) ## auto generated UUID 4&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;logger&#039;,logger)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;platform&#039;,platform)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;culprit&#039;,culprit)&lt;br /&gt;
#Do JSON.$addmember(&#039;&#039;,&#039;release&#039;,release)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;timestamp&#039;,timestamp)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;sdk&#039;,&#039;&#039;)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;message&#039;,pErrorText)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;level&#039;,pLevel)&lt;br /&gt;
Do JSON.$addmember(&#039;&#039;,&#039;tags&#039;,&#039;&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== HTTP-Kommunikation ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; sendet den erzeugten JSON-Payload an Sentry:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Generate HTTP Auth header&lt;br /&gt;
Begin text block&lt;br /&gt;
Text:Sentry sentry_version=7,&lt;br /&gt;
Text:sentry_timestamp=[$cinst.$getUnixTimestamp()],&lt;br /&gt;
Text:sentry_key=[iPubKey],&lt;br /&gt;
Text:sentry_client=omnis/1.0&lt;br /&gt;
End text block&lt;br /&gt;
Get text block auth&lt;br /&gt;
&lt;br /&gt;
#Generate header list&lt;br /&gt;
Calculate Host as &#039;sentry.io&#039;&lt;br /&gt;
Calculate Url as con(&#039;/api/&#039;,iProID,&#039;/store/&#039;)&lt;br /&gt;
Do HdrList.$define(wert,name)&lt;br /&gt;
Do HdrList.$add(&#039;User-Agent&#039;,&#039;omnis/1.0&#039;)&lt;br /&gt;
Do HdrList.$add(&#039;Content-Type&#039;,&#039;application/json&#039;)&lt;br /&gt;
Do HdrList.$add(&#039;Content-Length&#039;,binlength(json))&lt;br /&gt;
Do HdrList.$add(&#039;X-Sentry-Auth&#039;,auth)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anschließend wird der Request über &amp;lt;code&amp;gt;HTTPPost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HTTPSend&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;HTTPRead&amp;lt;/code&amp;gt; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
=== Fehlerbehandlung beim Senden ===&lt;br /&gt;
&lt;br /&gt;
Wenn der Socket nicht geöffnet werden kann:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
HTTPPost (Host,Url,,HdrList,443,kTrue,kTrue) Returns Socket&lt;br /&gt;
If Socket&amp;lt;0&lt;br /&gt;
	#Error when opening connection -&amp;gt; save json as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,con(&#039;Error &#039;,Socket,&#039; when performing HTTPPost&#039;))&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -1&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn das Senden fehlschlägt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
HTTPSend (Socket,json) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0&lt;br /&gt;
	# Error while sending data -&amp;gt; save json as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,con(&#039;Erorr &#039;,byteCount,&#039; when performing HTTPSend&#039;))&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -2&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn die Antwort nicht erfolgreich ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
HTTPRead (Socket,Buffer) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0|not(pos(&#039;200 OK&#039;,Buffer))&lt;br /&gt;
	# JSON may be corrupted or contains errors -&amp;gt; save json and the buffer as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,Buffer)&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -3&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Lokales Speichern ===&lt;br /&gt;
&lt;br /&gt;
Bei Fehlern wird der JSON Report lokal im Omnis-Installationsordner gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Writes the json and the http buffer to a file in the omnis installation folder&lt;br /&gt;
Calculate path as sys(115)&lt;br /&gt;
Calculate filename as con(&#039;Sentryreport_&#039;,$cinst.$getUnixTimestamp(),&#039;.json&#039;)&lt;br /&gt;
Do fOP.$createfile(con(path,filename)) Returns err&lt;br /&gt;
Do fOP.$writecharacter(kUniTypeUTF8,pJSON) Returns err&lt;br /&gt;
If not(isclear(pBuffer))&lt;br /&gt;
	Do fOP.$writecharacter(kUniTypeUTF8,con(kCr,pBuffer),kTrue) Returns err&lt;br /&gt;
End If&lt;br /&gt;
Do fOP.$closefile()&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cleanup ===&lt;br /&gt;
&lt;br /&gt;
Nach erfolgreichem Senden werden [[#Tags, Extras und User-Kontext|Tags und Extras]] gelöscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Clears all extras and tags =&amp;gt; to be used after a sentry request has successfully been sent&lt;br /&gt;
Do iTagList.$clear()&lt;br /&gt;
Do iExtraList.$clear()&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Demo Library ==&lt;br /&gt;
&lt;br /&gt;
Die Demo-Library zeigt, wie &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; initialisiert wird und wie verschiedene [[#Events erfassen|Event-Typen]] aus einer Omnis-Oberfläche heraus an Sentry gesendet werden.&lt;br /&gt;
&lt;br /&gt;
=== Bestandteile ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Zweck&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Startup_Task&amp;lt;/code&amp;gt; || Initialisiert Sentry, SQLite und öffnet das Demo-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; || Demo-Fenster&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODummy&amp;lt;/code&amp;gt; || Erzeugt Demo-Stack für Exception&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ODatabaseHandler&amp;lt;/code&amp;gt; || Erstellt SQLite-Demo-Datenbank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSLSession&amp;lt;/code&amp;gt; || SQLite Session&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; || Low-Level-Sentry-Adapter&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; || High-Level-Sentry-Adapter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt; initialisiert Sentry, baut eine SQLite Session auf und öffnet das Demo-Fenster. Quelle: &amp;lt;code&amp;gt;Startup_Task.$construct&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Init Sentry on lbs startup&lt;br /&gt;
Do tSentry.$init()&lt;br /&gt;
&lt;br /&gt;
#SQLite Session init&lt;br /&gt;
Do $objects.OSLSession.$newref() Returns tOSLSession&lt;br /&gt;
#Calculate tOSLSession.$opencreate as kTrue&lt;br /&gt;
Calculate workingDir as tODatabaseHandler.$getWorkingDir()&lt;br /&gt;
Do con(workingDir,&#039;Sentry_Test.db&#039;) Returns dbLocation&lt;br /&gt;
Do tOSLSession.$logon(dbLocation,&#039;&#039;,&#039;&#039;,&#039;slsession&#039;) Returns #F&lt;br /&gt;
&lt;br /&gt;
#Open Test Window&lt;br /&gt;
Do $windows.FSY_Demo.$openonce(&#039;*&#039;)&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Demo-Fenster ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FSY_Demo&amp;lt;/code&amp;gt; enthält folgende Bereiche:&lt;br /&gt;
&lt;br /&gt;
* DSN Configuration&lt;br /&gt;
* DB Status&lt;br /&gt;
* Actions&lt;br /&gt;
&lt;br /&gt;
Wichtige Felder:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feld !! Datenanbindung&lt;br /&gt;
|-&lt;br /&gt;
| DSN || &amp;lt;code&amp;gt;iDSN&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Host || &amp;lt;code&amp;gt;tSentry.iOSentry.iHost&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Public Key || &amp;lt;code&amp;gt;tSentry.iOSentry.iPubKey&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Project ID || &amp;lt;code&amp;gt;tSentry.iOSentry.iProID&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| DB Status || &amp;lt;code&amp;gt;iCurrentDBStatus&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Datei:demo-window.svg|thumb|Demo-Fenster der OSentry Library]]&lt;br /&gt;
&lt;br /&gt;
=== DSN setzen ===&lt;br /&gt;
&lt;br /&gt;
Die DSN wird im Feld &amp;lt;code&amp;gt;iDSN&amp;lt;/code&amp;gt; erfasst. Der Button &amp;lt;code&amp;gt;Set DSN&amp;lt;/code&amp;gt; ruft anschließend &amp;lt;code&amp;gt;tSentry.$init(iDSN)&amp;lt;/code&amp;gt; auf. Nach dem Setzen werden Public Key, Host und Project ID aus der DSN gelesen und in den darunterliegenden Feldern angezeigt.&lt;br /&gt;
&lt;br /&gt;
[[Datei:demo-dsn.svg|thumb|DSN-Konfiguration im Demo-Fenster]]&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Set DSN&amp;lt;/code&amp;gt; initialisiert Sentry mit der eingegebenen DSN. Quelle: &amp;lt;code&amp;gt;FSY_Demo.setDSN.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$init(iDSN)&lt;br /&gt;
	Calculate $cclass.$ivardefs.iDSN.$objinitval as con(kSq,iDSN,kSq)&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$showmessage(&#039;DSN set and Sentry initialized!&#039;,&#039;Info&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$redraw()&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== DB Status anzeigen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FSY_Demo.$displayDBState&amp;lt;/code&amp;gt; zeigt, ob die SQLite Session verbunden ist. Quelle: &amp;lt;code&amp;gt;FSY_Demo.$displayDBState&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tOSLSession.$state Returns dbState&lt;br /&gt;
If dbState=&#039;kSessionStateLoggedOff&#039;&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Logged Off&#039;&lt;br /&gt;
Else If dbState=&#039;kSessionStateLoggedOn&#039;&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Logged On&#039;&lt;br /&gt;
Else&lt;br /&gt;
	Calculate iCurrentDBStatus as &#039;Unkown DB State&#039;&lt;br /&gt;
End If&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$redraw()&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Demo-Datenbank erstellen ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Create Database&amp;lt;/code&amp;gt; ruft &amp;lt;code&amp;gt;ODatabaseHandler.$DBFirstInit&amp;lt;/code&amp;gt; auf. Quelle: &amp;lt;code&amp;gt;FSY_Demo.createDB.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Setup the DB&lt;br /&gt;
	Do tODatabaseHandler.$DBFirstInit() Returns err&lt;br /&gt;
	If err=0&lt;br /&gt;
		Do $cinst.$showmessage(&#039;DB successfully created!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Else&lt;br /&gt;
		Do $cinst.$showmessage(&#039;Error while creating the DB. Make sure that the DB does not already exist.&#039;,&#039;Info&#039;)&lt;br /&gt;
	End If&lt;br /&gt;
	&lt;br /&gt;
	Do $cinst.$displayDBState()&lt;br /&gt;
	&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Datenbank wird im Arbeitsverzeichnis der Library angelegt. Quelle: &amp;lt;code&amp;gt;ODatabaseHandler.$getWorkingDir&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Quit method con(FileOps.$parentdir($clib.$pathname),pathsep())&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Demo-DB enthält unter anderem:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;dperson&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;drelease&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;dvcs&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a message&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.message.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureMessage(&#039;Hello Euromnis! This is a test message...&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Log auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a log&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.log.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureLog(&#039;Uh oh this is a Log because something went wrong&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exception auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger an exception&amp;lt;/code&amp;gt; bereitet eine Row und eine List vor und ruft anschließend &amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt; auf. Quelle: &amp;lt;code&amp;gt;FSY_Demo.exception.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do iDummyRow.$define(id,name)&lt;br /&gt;
	Calculate iDummyRow.id as 22&lt;br /&gt;
	Calculate iDummyRow.name as &#039;Tom&#039;&lt;br /&gt;
	&lt;br /&gt;
	Do iDummyList.$define(id,weekday)&lt;br /&gt;
	Do iDummyList.$add(1,&#039;Monday&#039;)&lt;br /&gt;
	Do iDummyList.$add(2,&#039;Tuesday&#039;)&lt;br /&gt;
	Do iDummyList.$add(3,&#039;Wednesday&#039;)&lt;br /&gt;
	Do iDummyList.$add(4,&#039;Thursday&#039;)&lt;br /&gt;
	Do iDummyList.$add(5,&#039;Friday&#039;)&lt;br /&gt;
	Do iDummyList.$add(6,&#039;Saturday&#039;)&lt;br /&gt;
	Do iDummyList.$add(7,&#039;Sunday&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Calculate iDummyList.$line as 5&lt;br /&gt;
	&lt;br /&gt;
	Do iODummy.$dummyMethod(&#039;Important Value&#039;)&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt; sendet die Exception. Quelle: &amp;lt;code&amp;gt;ODummy.$dummyMethod&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#In here is some logic&lt;br /&gt;
#This logic would produce an error&lt;br /&gt;
#We send all this information to Sentry&lt;br /&gt;
&lt;br /&gt;
Do tSentry.$captureException(&#039;A generic Exception occured&#039;,1234,&#039;Generic Exception&#039;,&#039;error&#039;)&lt;br /&gt;
&lt;br /&gt;
Quit method 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deprecated Call auslösen ===&lt;br /&gt;
&lt;br /&gt;
Button &amp;lt;code&amp;gt;Trigger a deprecated call&amp;lt;/code&amp;gt;. Quelle: &amp;lt;code&amp;gt;FSY_Demo.deprecatedCall.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	Do tSentry.$captureDeprecatedCall()&lt;br /&gt;
	Do $cinst.$showmessage(&#039;Sentry Event successfully triggered!&#039;,&#039;Info&#039;)&lt;br /&gt;
	Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception Button ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Trigger an SQLException&amp;lt;/code&amp;gt; ist im Export vorhanden, enthält aber noch keinen fertigen Demo-Code. Quelle: &amp;lt;code&amp;gt;FSY_Demo.sqlException.$event&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Code need&#039;s to be written&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Dokumentation der SQL-Erfassung siehe [[#Events erfassen|03 Events erfassen]].&lt;br /&gt;
&lt;br /&gt;
== API Reference ==&lt;br /&gt;
&lt;br /&gt;
Diese Seite dokumentiert die produktiv relevanten Methoden von &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== OSentryHL ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt; ist die empfohlene Klasse für Applikationscode.&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$init(pDSN)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Initialisiert das interne &amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt;-Objekt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Init of the main sentry object&lt;br /&gt;
Do iOSentry.$init(pDSN)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$captureMessage(pMessage)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Sendet eine einfache Info-Message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Captures an Info Message&lt;br /&gt;
Do iOSentry.$captureException(pMessage,3,,&#039;info&#039;,kFalse,,kFalse) Returns code&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$captureException(pErrorText,pErrorCode,pExcType,pLevel)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Sendet eine generische Exception.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Method to capture a generic Exception&lt;br /&gt;
#Add any custom tags / extras&lt;br /&gt;
Do $cinst.$addTag(&#039;Custom Test Tag&#039;,&#039;Euromnis&#039;)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$captureAnything(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Sendet ein frei konfigurierbares Event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Capture a generic Sentry Report (max configurability)&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraveInterface,pExceptionInterface,pUserInterface) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hinweis: Der Parameter ist im Export als &amp;lt;code&amp;gt;pStacktraveInterface&amp;lt;/code&amp;gt; geschrieben.&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$captureLog(pErrorText)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Sendet ein Log-Event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Captures a Log Sentry Report&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;Log&#039;,&#039;warning&#039;,1,0,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$captureDeprecatedCall()&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Meldet die Ausführung eines veralteten Codepfads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Report a deprecated call of a piece of code to sentry&lt;br /&gt;
Do iOSentry.$captureException(&#039;Deprecated Call&#039;,3,&#039;Deprecated Call&#039;,&#039;warning&#039;,1,1,1) Returns code&lt;br /&gt;
&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$captureSQLException(pErrorText,pStat)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Meldet einen SQL-Fehler mit SQL-Text und nativer Datenbankfehlermeldung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Method to capture an SQL Exception&lt;br /&gt;
Do $cinst.$addTag(&#039;Database&#039;,tOSLSession.$hostname)&lt;br /&gt;
&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Text&#039;,pStat.$sqltext)&lt;br /&gt;
Do $cinst.$addExtra(&#039;SQL-Error&#039;,pStat.$nativeerrortext)&lt;br /&gt;
&lt;br /&gt;
Do iOSentry.$captureException(pErrorText,1,&#039;SQL-Exception&#039;,&#039;error&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$addTag(pName,pValue)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Fügt einen Tag für das nächste Event hinzu.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Add a Tag to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addTag(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$addExtra(pName,pValue)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Fügt ein Extra für das nächste Event hinzu.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Add an Extra to the next Sentry Report&lt;br /&gt;
Do iOSentry.$addExtra(pName,pValue)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$setStatus(pStatus)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Aktiviert oder deaktiviert Sentry.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Toggels Sentry on or off&lt;br /&gt;
Do iOSentry.$setStatus(pStatus)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$setUser()&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Setzt im Export feste [[#Demo Library|Demo]]-Userdaten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Set the User which should be linked to the Sentry Issue&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte diese Methode parametrisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== OSentry ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry&amp;lt;/code&amp;gt; ist die Low-Level-Klasse für Payload-Erzeugung und Versand.&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$init(pDSN)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Parst die DSN in Protokoll, Public Key, Host und Project ID.&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$captureException(pErrorText,pErrorCode,pExcType,pLevel,pStacktraceInterface,pUserInterface,pExceptionInterface)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Erzeugt JSON, sendet es an Sentry und behandelt Fehlerfälle.&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Default !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorText&amp;lt;/code&amp;gt; ||  || Message&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pErrorCode&amp;lt;/code&amp;gt; ||  || Fehlercode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExcType&amp;lt;/code&amp;gt; ||  || Exception-Typ&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pLevel&amp;lt;/code&amp;gt; ||  || &amp;lt;code&amp;gt;fatal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pStacktraceInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || [[#Stacktrace und Kontext|Stacktrace]] senden&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pUserInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || [[#Tags, Extras und User-Kontext|User-Kontext]] senden&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pExceptionInterface&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;kTrue&amp;lt;/code&amp;gt; || Exception Interface senden&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$generateJson(...)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Erzeugt den Sentry JSON Payload als Binary.&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$generateStacktraceInterface(pCulprit)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Erzeugt den Omnis-[[#Stacktrace und Kontext|Stacktrace]] inklusive Variablen und Kontextzeilen.&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$generateExceptionInterface(pType,pValue)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Erzeugt das Sentry Exception Interface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Generate Row to store in the JSON&lt;br /&gt;
Do exceptionRow.$define(type,value,stacktrace)&lt;br /&gt;
Calculate exceptionRow.type as pType&lt;br /&gt;
Calculate exceptionRow.value as pValue&lt;br /&gt;
Calculate exceptionRow.stacktrace as &#039;sentry.interfaces.stacktrace&#039; ## Tells the exception interface that a stacktrace is passed aswell&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$generateUserInterface()&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Erzeugt den [[#Tags, Extras und User-Kontext|User-Kontext]].&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$addTag(pName,pValue)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Fügt einen Tag zur internen Tag-Liste hinzu.&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$addExtra(pName,pValue)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Fügt ein Extra zur internen Extra-Liste hinzu.&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$clearList()&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Leert [[#Tags, Extras und User-Kontext|Tags und Extras]] nach einem Request.&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$setUserData(pID,pName,pEmail)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Setzt Userdaten für den nächsten Request.&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$setProxy(pProxyHost,pProxyPort)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Setzt Proxy-Informationen.&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$setStatus(pStatus)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Setzt den Sentry-Status.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Toggels Sentry Reports on or off&lt;br /&gt;
Calculate iStatus as pStatus&lt;br /&gt;
Quit method&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$writeJSON(pJSON,pBuffer)&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Schreibt fehlgeschlagene Reports lokal in eine Datei.&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$getUnixTimestamp()&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Gibt den aktuellen UNIX Timestamp zurück.&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;$generateUUID()&amp;lt;/code&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
Erzeugt eine UUID für die Sentry Event ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Genereates a UUID for the issue id&lt;br /&gt;
Quit method OW3.$makeuuid(kFalse)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Es erscheinen keine Events in Sentry ===&lt;br /&gt;
&lt;br /&gt;
Prüfe zuerst, ob Sentry aktiv ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$setStatus(1)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentry.$captureException&amp;lt;/code&amp;gt; beendet sich sofort, wenn der Status &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; oder leer ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#Check if Sentry is enabled&lt;br /&gt;
If iStatus=0|isclear(iStatus)&lt;br /&gt;
	Quit method 0&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Die DSN ist falsch ===&lt;br /&gt;
&lt;br /&gt;
Prüfe, ob die DSN korrekt aus Sentry kopiert wurde. &amp;lt;code&amp;gt;OSentry.$init&amp;lt;/code&amp;gt; erwartet eine DSN, aus der Public Key, Host und Project ID gelesen werden können.&lt;br /&gt;
&lt;br /&gt;
Nach dem Setzen der DSN sollten in der [[#Demo Library|Demo-Library]] folgende Felder gefüllt sein:&lt;br /&gt;
&lt;br /&gt;
* Host&lt;br /&gt;
* Public Key&lt;br /&gt;
* Project ID&lt;br /&gt;
&lt;br /&gt;
=== Netzwerk oder Proxy blockiert den Request ===&lt;br /&gt;
&lt;br /&gt;
Wenn die Anwendung keinen direkten Zugriff auf Sentry hat, setze einen Proxy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.iOSentry.$setProxy(&#039;proxy.example.local&#039;,&#039;8080&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Intern wird der Proxy vor dem HTTP Request gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
If not(isclear(iProxyHost))&amp;amp;not(isclear(iProxyPort))&lt;br /&gt;
	HTTPSetProxyServer (iProxyHost,iProxyPort)&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Report wird lokal gespeichert ===&lt;br /&gt;
&lt;br /&gt;
Wenn &amp;lt;code&amp;gt;HTTPPost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HTTPSend&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;HTTPRead&amp;lt;/code&amp;gt; fehlschlägt, speichert OSentry den Report lokal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Calculate path as sys(115)&lt;br /&gt;
Calculate filename as con(&#039;Sentryreport_&#039;,$cinst.$getUnixTimestamp(),&#039;.json&#039;)&lt;br /&gt;
Do fOP.$createfile(con(path,filename)) Returns err&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Suche im Omnis-Installationsordner nach Dateien mit dem Namen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Sentryreport_&amp;lt;timestamp&amp;gt;.json&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sentry antwortet nicht mit 200 OK ===&lt;br /&gt;
&lt;br /&gt;
Wenn die HTTP-Antwort kein &amp;lt;code&amp;gt;200 OK&amp;lt;/code&amp;gt; enthält, wird der JSON Report ebenfalls lokal gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
HTTPRead (Socket,Buffer) Returns byteCount&lt;br /&gt;
If byteCount&amp;lt;0|not(pos(&#039;200 OK&#039;,Buffer))&lt;br /&gt;
	# JSON may be corrupted or contains errors -&amp;gt; save json and the buffer as a file&lt;br /&gt;
	Do $cinst.$writeJSON(iJSON,Buffer)&lt;br /&gt;
	Do $cinst.$clearList()&lt;br /&gt;
	HTTPClose (Socket)&lt;br /&gt;
	Quit method -3&lt;br /&gt;
End If&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mögliche Ursachen:&lt;br /&gt;
&lt;br /&gt;
* falsche Project ID&lt;br /&gt;
* falscher Public Key&lt;br /&gt;
* ungültige DSN&lt;br /&gt;
* JSON Payload wird von Sentry abgelehnt&lt;br /&gt;
* Netzwerk-Gateway verändert den Request&lt;br /&gt;
&lt;br /&gt;
=== Tags oder Extras erscheinen beim falschen Event ===&lt;br /&gt;
&lt;br /&gt;
[[#Tags, Extras und User-Kontext|Tags und Extras]] werden für den nächsten Request gesammelt. Nach erfolgreichem Request werden sie gelöscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do iTagList.$clear()&lt;br /&gt;
Do iExtraList.$clear()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn ein Request fehlschlägt, wird ebenfalls aufgeräumt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do $cinst.$clearList()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prüfe trotzdem, ob in eigenen Wrapper-Methoden Tags und Extras direkt vor dem passenden Capture-Aufruf gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== User-Kontext zeigt Demo-Daten ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OSentryHL.$setUser&amp;lt;/code&amp;gt; verwendet im Export feste Testdaten:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(23,&#039;Euromnis Test User&#039;,&#039;euromnis@test.com&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für produktive Nutzung sollte die Methode parametrisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do iOSentry.$setUserData(pUserID,pUserName,pUserEmail)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SQL Exception Demo-Button funktioniert nicht ===&lt;br /&gt;
&lt;br /&gt;
Der Button &amp;lt;code&amp;gt;Trigger an SQLException&amp;lt;/code&amp;gt; ist im Export noch nicht implementiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
On evClick ## Event Parameters - pRow( Itemreference )&lt;br /&gt;
	#Code need&#039;s to be written&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die produktive Methode für SQL-Fehler ist aber vorhanden. Siehe auch [[#Events erfassen|Events erfassen]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Do tSentry.$captureSQLException(&#039;SQL statement failed&#039;,stat)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Zu viele Events ===&lt;br /&gt;
&lt;br /&gt;
Sentry kann sehr schnell viele Events sammeln. Verwende für produktive Systeme:&lt;br /&gt;
&lt;br /&gt;
* klare Wrapper-Methoden in &amp;lt;code&amp;gt;OSentryHL&amp;lt;/code&amp;gt;&lt;br /&gt;
* sinnvolle Levels&lt;br /&gt;
* gezielte [[#Tags, Extras und User-Kontext|Tags]]&lt;br /&gt;
* keine Events in sehr häufigen Schleifen&lt;br /&gt;
* keine rein informativen Debug-Events ohne Nutzen&lt;br /&gt;
&lt;br /&gt;
=== Sensible Daten ===&lt;br /&gt;
&lt;br /&gt;
[[#Stacktrace und Kontext|Stacktrace]], Parameter, Instance Variablen, SQL-Text und [[#Tags, Extras und User-Kontext|Extras]] können sensible Daten enthalten. Prüfe vor produktiver Nutzung:&lt;br /&gt;
&lt;br /&gt;
* Welche Variablen werden übertragen?&lt;br /&gt;
* Enthalten SQL-Statements personenbezogene Daten?&lt;br /&gt;
* Werden Tokens oder Passwörter in Extras geschrieben?&lt;br /&gt;
* Sollen bestimmte Werte maskiert werden?&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Datei:Demo-window.png&amp;diff=9525</id>
		<title>Datei:Demo-window.png</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Datei:Demo-window.png&amp;diff=9525"/>
		<updated>2026-06-12T13:58:35Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Datei:Demo-dsn.png&amp;diff=9524</id>
		<title>Datei:Demo-dsn.png</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Datei:Demo-dsn.png&amp;diff=9524"/>
		<updated>2026-06-12T13:58:21Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Datei:Sentry-tags.png&amp;diff=9523</id>
		<title>Datei:Sentry-tags.png</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Datei:Sentry-tags.png&amp;diff=9523"/>
		<updated>2026-06-12T13:55:30Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Datei:Sentry-stack.png&amp;diff=9522</id>
		<title>Datei:Sentry-stack.png</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Datei:Sentry-stack.png&amp;diff=9522"/>
		<updated>2026-06-12T13:55:20Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Datei:Sentry-projects.png&amp;diff=9521</id>
		<title>Datei:Sentry-projects.png</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Datei:Sentry-projects.png&amp;diff=9521"/>
		<updated>2026-06-12T13:55:10Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Datei:Sentry-issue.png&amp;diff=9520</id>
		<title>Datei:Sentry-issue.png</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Datei:Sentry-issue.png&amp;diff=9520"/>
		<updated>2026-06-12T13:54:58Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Entausschiessen&amp;diff=9431</id>
		<title>Entausschiessen</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Entausschiessen&amp;diff=9431"/>
		<updated>2026-01-28T10:33:14Z</updated>

		<summary type="html">&lt;p&gt;Silvan: /* Anwendungsbeispiel */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge:&lt;br /&gt;
  3583&lt;br /&gt;
;Systemtyp:&lt;br /&gt;
  79&lt;br /&gt;
&lt;br /&gt;
== Beschreibung ==&lt;br /&gt;
Dieser Serverjob führt einen &#039;&#039;&#039;Entausschiessen-Algorithmus&#039;&#039;&#039; aus.  &lt;br /&gt;
Er wird eingesetzt, wenn z. B. &#039;&#039;&#039;Broschüren oder geheftete Dokumente&#039;&#039;&#039; (Bostitch/Klammer entfernt) geöffnet und anschliessend über einen &#039;&#039;&#039;Durchlaufscanner&#039;&#039;&#039; digitalisiert werden.&lt;br /&gt;
&lt;br /&gt;
Ein Durchlaufscanner erfasst jeweils eine &#039;&#039;&#039;aufgeklappte Doppelseite&#039;&#039;&#039;.  &lt;br /&gt;
&#039;&#039;&#039;Jede gescannte Seite wird dabei in zwei einzelne Bilddateien aufgetrennt.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dabei entsteht eine Bildreihenfolge, die nicht der logischen Seitenreihenfolge des Dokuments entspricht:&lt;br /&gt;
&lt;br /&gt;
* Bei der &#039;&#039;&#039;ersten gescannten Seite&#039;&#039;&#039; ist  &lt;br /&gt;
** das &#039;&#039;&#039;erste Bild&#039;&#039;&#039; die &#039;&#039;&#039;letzte Seite&#039;&#039;&#039; der Broschüre  &lt;br /&gt;
** das &#039;&#039;&#039;zweite Bild&#039;&#039;&#039; die &#039;&#039;&#039;erste Seite&#039;&#039;&#039; der Broschüre&lt;br /&gt;
* Bei den &#039;&#039;&#039;folgenden Scans&#039;&#039;&#039; alterniert die Reihenfolge der aufgetrennten Bilder (aussen nach innen)&lt;br /&gt;
&lt;br /&gt;
Der Serverjob bringt diese aufgetrennten Bilder automatisch in die korrekte Reihenfolge.&lt;br /&gt;
&lt;br /&gt;
== Funktionsweise ==&lt;br /&gt;
Ausgehend von einer Liste mit &#039;&#039;N&#039;&#039; Bilddateien (Einzelseiten), welche aus dem Auftrennen der gescannten Doppelseiten entstehen, ordnet der Algorithmus die Seiten nach dem Prinzip &#039;&#039;&#039;aussen nach innen&#039;&#039;&#039; neu an.&lt;br /&gt;
&lt;br /&gt;
Die resultierende Reihenfolge folgt diesem Muster:&lt;br /&gt;
&lt;br /&gt;
* letztes Dokumentblatt&lt;br /&gt;
* erstes Dokumentblatt&lt;br /&gt;
* zweites Dokumentblatt&lt;br /&gt;
* zweitletztes Dokumentblatt&lt;br /&gt;
* usw.&lt;br /&gt;
&lt;br /&gt;
Nach der Neuordnung werden die Dateien fortlaufend neu nummeriert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;0001.tif … 000N.tif&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mathematische Beschreibung ==&lt;br /&gt;
Es sei &#039;&#039;N&#039;&#039; die Anzahl der &#039;&#039;&#039;aufgetrennten Einzelseiten&#039;&#039;&#039; (nicht der gescannten Doppelseiten).&lt;br /&gt;
&lt;br /&gt;
Die Eingabe für den Algorithmus ist eine Liste von &#039;&#039;N&#039;&#039; Bildern, welche durch das Auftrennen der gescannten Doppelseiten entstehen.  &lt;br /&gt;
Diese Liste entspricht einer Reihenfolge von außen nach innen.&lt;br /&gt;
&lt;br /&gt;
Für eine Zielposition &amp;lt;code&amp;gt;k&amp;lt;/code&amp;gt; mit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;1 ≤ k ≤ N&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
berechnet der Algorithmus, welche physische Seite an dieser Position stehen soll.&lt;br /&gt;
&lt;br /&gt;
Die Zuordnung erfolgt über die Funktion &amp;lt;code&amp;gt;f(k)&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
f(k) =&lt;br /&gt;
  N - ⌊(k-1)/2⌋    falls k ≡ 1 (mod 4)&lt;br /&gt;
  1 + ⌊(k-2)/2⌋    falls k ≡ 2 (mod 4)&lt;br /&gt;
  1 + ⌊(k-3)/2⌋    falls k ≡ 3 (mod 4)&lt;br /&gt;
  N - ⌊(k-4)/2⌋    falls k ≡ 0 (mod 4)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispielrechnung ===&lt;br /&gt;
Gegeben sei ein Dokument mit &amp;lt;code&amp;gt;N = 8&amp;lt;/code&amp;gt; Einzelseiten und die Zielposition &amp;lt;code&amp;gt;k = 5&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird die Modulo-Klasse bestimmt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;5 mod 4 = 1&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit gilt der erste Fall der Definition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
f(5) = 8 − ⌊(5−1)/2⌋&lt;br /&gt;
     = 8 − ⌊2⌋&lt;br /&gt;
     = 6&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das bedeutet:  &lt;br /&gt;
&#039;&#039;&#039;Die Zielposition 0005 enthält die physische Seite 6.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Anwendungsbeispiel ==&lt;br /&gt;
Eine Broschüre mit 8 physischen Seiten wird geöffnet (Bostitch entfernt) und über einen Durchlaufscanner digitalisiert.&lt;br /&gt;
&lt;br /&gt;
Der Scanner erfasst aufgeklappte Doppelseiten.  &lt;br /&gt;
Jede gescannte Seite wird anschließend in zwei Bilder aufgetrennt.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Gescannte Seite !! Bild 1 !! Bild 2&lt;br /&gt;
|-&lt;br /&gt;
| Scan 1 || Seite 8 || Seite 1&lt;br /&gt;
|-&lt;br /&gt;
| Scan 2 || Seite 2 || Seite 7&lt;br /&gt;
|-&lt;br /&gt;
| Scan 3 || Seite 6 || Seite 3&lt;br /&gt;
|-&lt;br /&gt;
| Scan 4 || Seite 4 || Seite 5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Daraus ergibt sich folgende Bildliste (Eingabe für den Serverjob):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;(8, 1, 2, 7, 6, 3, 4, 5)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bezug zur mathematischen Beschreibung ===&lt;br /&gt;
Für die Zielposition &amp;lt;code&amp;gt;k = 5&amp;lt;/code&amp;gt; ergibt die mathematische Funktion:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;f(5) = 6&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der fünfte Eintrag der Bildliste ist ebenfalls &#039;&#039;&#039;Seite 6&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Zielposition !! Physische Seite&lt;br /&gt;
|-&lt;br /&gt;
| 0005 || 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Entausschiessen&amp;diff=9430</id>
		<title>Entausschiessen</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Entausschiessen&amp;diff=9430"/>
		<updated>2026-01-28T10:33:02Z</updated>

		<summary type="html">&lt;p&gt;Silvan: /* Mathematische Beschreibung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge:&lt;br /&gt;
  3583&lt;br /&gt;
;Systemtyp:&lt;br /&gt;
  79&lt;br /&gt;
&lt;br /&gt;
== Beschreibung ==&lt;br /&gt;
Dieser Serverjob führt einen &#039;&#039;&#039;Entausschiessen-Algorithmus&#039;&#039;&#039; aus.  &lt;br /&gt;
Er wird eingesetzt, wenn z. B. &#039;&#039;&#039;Broschüren oder geheftete Dokumente&#039;&#039;&#039; (Bostitch/Klammer entfernt) geöffnet und anschliessend über einen &#039;&#039;&#039;Durchlaufscanner&#039;&#039;&#039; digitalisiert werden.&lt;br /&gt;
&lt;br /&gt;
Ein Durchlaufscanner erfasst jeweils eine &#039;&#039;&#039;aufgeklappte Doppelseite&#039;&#039;&#039;.  &lt;br /&gt;
&#039;&#039;&#039;Jede gescannte Seite wird dabei in zwei einzelne Bilddateien aufgetrennt.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dabei entsteht eine Bildreihenfolge, die nicht der logischen Seitenreihenfolge des Dokuments entspricht:&lt;br /&gt;
&lt;br /&gt;
* Bei der &#039;&#039;&#039;ersten gescannten Seite&#039;&#039;&#039; ist  &lt;br /&gt;
** das &#039;&#039;&#039;erste Bild&#039;&#039;&#039; die &#039;&#039;&#039;letzte Seite&#039;&#039;&#039; der Broschüre  &lt;br /&gt;
** das &#039;&#039;&#039;zweite Bild&#039;&#039;&#039; die &#039;&#039;&#039;erste Seite&#039;&#039;&#039; der Broschüre&lt;br /&gt;
* Bei den &#039;&#039;&#039;folgenden Scans&#039;&#039;&#039; alterniert die Reihenfolge der aufgetrennten Bilder (aussen nach innen)&lt;br /&gt;
&lt;br /&gt;
Der Serverjob bringt diese aufgetrennten Bilder automatisch in die korrekte Reihenfolge.&lt;br /&gt;
&lt;br /&gt;
== Funktionsweise ==&lt;br /&gt;
Ausgehend von einer Liste mit &#039;&#039;N&#039;&#039; Bilddateien (Einzelseiten), welche aus dem Auftrennen der gescannten Doppelseiten entstehen, ordnet der Algorithmus die Seiten nach dem Prinzip &#039;&#039;&#039;aussen nach innen&#039;&#039;&#039; neu an.&lt;br /&gt;
&lt;br /&gt;
Die resultierende Reihenfolge folgt diesem Muster:&lt;br /&gt;
&lt;br /&gt;
* letztes Dokumentblatt&lt;br /&gt;
* erstes Dokumentblatt&lt;br /&gt;
* zweites Dokumentblatt&lt;br /&gt;
* zweitletztes Dokumentblatt&lt;br /&gt;
* usw.&lt;br /&gt;
&lt;br /&gt;
Nach der Neuordnung werden die Dateien fortlaufend neu nummeriert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;0001.tif … 000N.tif&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mathematische Beschreibung ==&lt;br /&gt;
Es sei &#039;&#039;N&#039;&#039; die Anzahl der &#039;&#039;&#039;aufgetrennten Einzelseiten&#039;&#039;&#039; (nicht der gescannten Doppelseiten).&lt;br /&gt;
&lt;br /&gt;
Die Eingabe für den Algorithmus ist eine Liste von &#039;&#039;N&#039;&#039; Bildern, welche durch das Auftrennen der gescannten Doppelseiten entstehen.  &lt;br /&gt;
Diese Liste entspricht einer Reihenfolge von außen nach innen.&lt;br /&gt;
&lt;br /&gt;
Für eine Zielposition &amp;lt;code&amp;gt;k&amp;lt;/code&amp;gt; mit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;1 ≤ k ≤ N&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
berechnet der Algorithmus, welche physische Seite an dieser Position stehen soll.&lt;br /&gt;
&lt;br /&gt;
Die Zuordnung erfolgt über die Funktion &amp;lt;code&amp;gt;f(k)&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
f(k) =&lt;br /&gt;
  N - ⌊(k-1)/2⌋    falls k ≡ 1 (mod 4)&lt;br /&gt;
  1 + ⌊(k-2)/2⌋    falls k ≡ 2 (mod 4)&lt;br /&gt;
  1 + ⌊(k-3)/2⌋    falls k ≡ 3 (mod 4)&lt;br /&gt;
  N - ⌊(k-4)/2⌋    falls k ≡ 0 (mod 4)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispielrechnung ===&lt;br /&gt;
Gegeben sei ein Dokument mit &amp;lt;code&amp;gt;N = 8&amp;lt;/code&amp;gt; Einzelseiten und die Zielposition &amp;lt;code&amp;gt;k = 5&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird die Modulo-Klasse bestimmt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;5 mod 4 = 1&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit gilt der erste Fall der Definition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
f(5) = 8 − ⌊(5−1)/2⌋&lt;br /&gt;
     = 8 − ⌊2⌋&lt;br /&gt;
     = 6&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das bedeutet:  &lt;br /&gt;
&#039;&#039;&#039;Die Zielposition 0005 enthält die physische Seite 6.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Anwendungsbeispiel ==&lt;br /&gt;
Eine Broschüre mit 8 physischen Seiten wird geöffnet (Bostitch entfernt) und über einen Durchlaufscanner digitalisiert.&lt;br /&gt;
&lt;br /&gt;
Der Scanner erfasst aufgeklappte Doppelseiten.  &lt;br /&gt;
Jede gescannte Seite wird anschließend in zwei Bilder aufgetrennt.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Gescannte Seite !! Bild 1 !! Bild 2&lt;br /&gt;
|-&lt;br /&gt;
| Scan 1 || Seite 8 || Seite 1&lt;br /&gt;
|-&lt;br /&gt;
| Scan 2 || Seite 2 || Seite 7&lt;br /&gt;
|-&lt;br /&gt;
| Scan 3 || Seite 6 || Seite 3&lt;br /&gt;
|-&lt;br /&gt;
| Scan 4 || Seite 4 || Seite 5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Daraus ergibt sich folgende Bildliste (Eingabe für den Serverjob):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;(8, 1, 2, 7, 6, 3, 4, 5)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bezug zur mathematischen Beschreibung ===&lt;br /&gt;
Für die Zielposition &amp;lt;code&amp;gt;k = 5&amp;lt;/code&amp;gt; ergibt die mathematische Funktion:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;f(5) = 6&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der fünfte Eintrag der Bildliste ist ebenfalls &#039;&#039;&#039;Seite 6&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Zielposition !! Physische Seite&lt;br /&gt;
|-&lt;br /&gt;
| 0005 || 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Damit ist gezeigt, dass die mathematische Beschreibung exakt der tatsächlichen Scan- und Auftrennreihenfolge entspricht.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Entausschiessen&amp;diff=9429</id>
		<title>Entausschiessen</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Entausschiessen&amp;diff=9429"/>
		<updated>2026-01-28T10:31:49Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge:&lt;br /&gt;
  3583&lt;br /&gt;
;Systemtyp:&lt;br /&gt;
  79&lt;br /&gt;
&lt;br /&gt;
== Beschreibung ==&lt;br /&gt;
Dieser Serverjob führt einen &#039;&#039;&#039;Entausschiessen-Algorithmus&#039;&#039;&#039; aus.  &lt;br /&gt;
Er wird eingesetzt, wenn z. B. &#039;&#039;&#039;Broschüren oder geheftete Dokumente&#039;&#039;&#039; (Bostitch/Klammer entfernt) geöffnet und anschliessend über einen &#039;&#039;&#039;Durchlaufscanner&#039;&#039;&#039; digitalisiert werden.&lt;br /&gt;
&lt;br /&gt;
Ein Durchlaufscanner erfasst jeweils eine &#039;&#039;&#039;aufgeklappte Doppelseite&#039;&#039;&#039;.  &lt;br /&gt;
&#039;&#039;&#039;Jede gescannte Seite wird dabei in zwei einzelne Bilddateien aufgetrennt.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dabei entsteht eine Bildreihenfolge, die nicht der logischen Seitenreihenfolge des Dokuments entspricht:&lt;br /&gt;
&lt;br /&gt;
* Bei der &#039;&#039;&#039;ersten gescannten Seite&#039;&#039;&#039; ist  &lt;br /&gt;
** das &#039;&#039;&#039;erste Bild&#039;&#039;&#039; die &#039;&#039;&#039;letzte Seite&#039;&#039;&#039; der Broschüre  &lt;br /&gt;
** das &#039;&#039;&#039;zweite Bild&#039;&#039;&#039; die &#039;&#039;&#039;erste Seite&#039;&#039;&#039; der Broschüre&lt;br /&gt;
* Bei den &#039;&#039;&#039;folgenden Scans&#039;&#039;&#039; alterniert die Reihenfolge der aufgetrennten Bilder (aussen nach innen)&lt;br /&gt;
&lt;br /&gt;
Der Serverjob bringt diese aufgetrennten Bilder automatisch in die korrekte Reihenfolge.&lt;br /&gt;
&lt;br /&gt;
== Funktionsweise ==&lt;br /&gt;
Ausgehend von einer Liste mit &#039;&#039;N&#039;&#039; Bilddateien (Einzelseiten), welche aus dem Auftrennen der gescannten Doppelseiten entstehen, ordnet der Algorithmus die Seiten nach dem Prinzip &#039;&#039;&#039;aussen nach innen&#039;&#039;&#039; neu an.&lt;br /&gt;
&lt;br /&gt;
Die resultierende Reihenfolge folgt diesem Muster:&lt;br /&gt;
&lt;br /&gt;
* letztes Dokumentblatt&lt;br /&gt;
* erstes Dokumentblatt&lt;br /&gt;
* zweites Dokumentblatt&lt;br /&gt;
* zweitletztes Dokumentblatt&lt;br /&gt;
* usw.&lt;br /&gt;
&lt;br /&gt;
Nach der Neuordnung werden die Dateien fortlaufend neu nummeriert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;0001.tif … 000N.tif&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mathematische Beschreibung ==&lt;br /&gt;
Es sei &#039;&#039;N&#039;&#039; die Anzahl der &#039;&#039;&#039;aufgetrennten Einzelseiten&#039;&#039;&#039; (nicht der gescannten Doppelseiten).&lt;br /&gt;
&lt;br /&gt;
Die Eingabe für den Algorithmus ist eine Liste von &#039;&#039;N&#039;&#039; Bildern, welche durch das Auftrennen der gescannten Doppelseiten entstehen.  &lt;br /&gt;
Diese Liste entspricht einer Reihenfolge von außen nach innen.&lt;br /&gt;
&lt;br /&gt;
Für eine Zielposition &amp;lt;code&amp;gt;k&amp;lt;/code&amp;gt; mit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;1 ≤ k ≤ N&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
berechnet der Algorithmus, welche physische Seite an dieser Position stehen soll.&lt;br /&gt;
&lt;br /&gt;
Die Zuordnung erfolgt über die Funktion &amp;lt;code&amp;gt;f(k)&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
f(k) =&lt;br /&gt;
  N - ⌊(k-1)/2⌋    falls k ≡ 1 (mod 4)&lt;br /&gt;
  1 + ⌊(k-2)/2⌋    falls k ≡ 2 (mod 4)&lt;br /&gt;
  1 + ⌊(k-3)/2⌋    falls k ≡ 3 (mod 4)&lt;br /&gt;
  N - ⌊(k-4)/2⌋    falls k ≡ 0 (mod 4)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispielrechnung ===&lt;br /&gt;
Gegeben sei ein Dokument mit &amp;lt;code&amp;gt;N = 8&amp;lt;/code&amp;gt; Einzelseiten und die Zielposition &amp;lt;code&amp;gt;k = 5&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird die Modulo-Klasse bestimmt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;5 mod 4 = 1&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit gilt der erste Fall der Definition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
f(5) = 8 − ⌊(5−1)/2⌋&lt;br /&gt;
     = 8 − ⌊2⌋&lt;br /&gt;
     = 6&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das bedeutet:  &lt;br /&gt;
&#039;&#039;&#039;Die Zielposition 0005 enthält die physische Seite 6.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Anwendungsbeispiel ==&lt;br /&gt;
Eine Broschüre mit 8 physischen Seiten wird geöffnet (Bostitch entfernt) und über einen Durchlaufscanner digitalisiert.&lt;br /&gt;
&lt;br /&gt;
Der Scanner erfasst aufgeklappte Doppelseiten.  &lt;br /&gt;
Jede gescannte Seite wird anschließend in zwei Bilder aufgetrennt.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Gescannte Seite !! Bild 1 !! Bild 2&lt;br /&gt;
|-&lt;br /&gt;
| Scan 1 || Seite 8 || Seite 1&lt;br /&gt;
|-&lt;br /&gt;
| Scan 2 || Seite 2 || Seite 7&lt;br /&gt;
|-&lt;br /&gt;
| Scan 3 || Seite 6 || Seite 3&lt;br /&gt;
|-&lt;br /&gt;
| Scan 4 || Seite 4 || Seite 5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Daraus ergibt sich folgende Bildliste (Eingabe für den Serverjob):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;(8, 1, 2, 7, 6, 3, 4, 5)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bezug zur mathematischen Beschreibung ===&lt;br /&gt;
Für die Zielposition &amp;lt;code&amp;gt;k = 5&amp;lt;/code&amp;gt; ergibt die mathematische Funktion:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;f(5) = 6&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der fünfte Eintrag der Bildliste ist ebenfalls &#039;&#039;&#039;Seite 6&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Zielposition !! Physische Seite&lt;br /&gt;
|-&lt;br /&gt;
| 0005 || 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Damit ist gezeigt, dass die mathematische Beschreibung exakt der tatsächlichen Scan- und Auftrennreihenfolge entspricht.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Entausschiessen&amp;diff=9428</id>
		<title>Entausschiessen</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Entausschiessen&amp;diff=9428"/>
		<updated>2026-01-28T10:20:17Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3583: Neuer Wikieintrag&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge:&lt;br /&gt;
  3583&lt;br /&gt;
;Systemtyp:&lt;br /&gt;
  79&lt;br /&gt;
&lt;br /&gt;
== Beschreibung ==&lt;br /&gt;
Dieser Serverjob führt einen &#039;&#039;&#039;Entausschiessen-Algorithmus&#039;&#039;&#039; aus.  &lt;br /&gt;
Er wird eingesetzt, wenn z. B. &#039;&#039;&#039;Broschüren oder geheftete Dokumente&#039;&#039;&#039; (Bostitch/Klammer entfernt) geöffnet und anschliessend über einen &#039;&#039;&#039;Durchlaufscanner&#039;&#039;&#039; digitalisiert werden.&lt;br /&gt;
&lt;br /&gt;
Ein Durchlaufscanner erfasst jeweils eine &#039;&#039;&#039;aufgeklappte Doppelseite&#039;&#039;&#039;.  &lt;br /&gt;
&#039;&#039;&#039;Jede gescannte Seite wird dabei in zwei einzelne Bilddateien aufgetrennt.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dabei entsteht eine Bildreihenfolge, die nicht der logischen Seitenreihenfolge des Dokuments entspricht:&lt;br /&gt;
&lt;br /&gt;
* Bei der &#039;&#039;&#039;ersten gescannten Seite&#039;&#039;&#039; ist  &lt;br /&gt;
** das &#039;&#039;&#039;erste Bild&#039;&#039;&#039; die &#039;&#039;&#039;letzte Seite&#039;&#039;&#039; der Broschüre  &lt;br /&gt;
** das &#039;&#039;&#039;zweite Bild&#039;&#039;&#039; die &#039;&#039;&#039;erste Seite&#039;&#039;&#039; der Broschüre&lt;br /&gt;
* Bei den &#039;&#039;&#039;folgenden Scans&#039;&#039;&#039; alterniert die Reihenfolge der aufgetrennten Bilder (aussen nach innen)&lt;br /&gt;
&lt;br /&gt;
Der Serverjob bringt diese aufgetrennten Bilder automatisch in die korrekte Reihenfolge.&lt;br /&gt;
&lt;br /&gt;
== Funktionsweise ==&lt;br /&gt;
Ausgehend von einer Liste mit &#039;&#039;N&#039;&#039; Bilddateien (Einzelseiten), welche aus dem Auftrennen der gescannten Doppelseiten entstehen, ordnet der Algorithmus die Seiten nach dem Prinzip &#039;&#039;&#039;aussen nach innen&#039;&#039;&#039; neu an.&lt;br /&gt;
&lt;br /&gt;
Die resultierende Reihenfolge folgt diesem Muster:&lt;br /&gt;
&lt;br /&gt;
* letztes Dokumentblatt&lt;br /&gt;
* erstes Dokumentblatt&lt;br /&gt;
* zweites Dokumentblatt&lt;br /&gt;
* zweitletztes Dokumentblatt&lt;br /&gt;
* usw.&lt;br /&gt;
&lt;br /&gt;
Nach der Neuordnung werden die Dateien fortlaufend neu nummeriert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;0001.tif … 000N.tif&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mathematische Beschreibung ==&lt;br /&gt;
Gegeben sei eine Folge von &#039;&#039;N&#039;&#039; Einzelseiten in logischer Reihenfolge:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;S = (1, 2, 3, …, N)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Durch das Scannen und Auftrennen der Doppelseiten entsteht eine Eingabereihenfolge, die von aussen nach innen verläuft.&lt;br /&gt;
&lt;br /&gt;
Der Entausschiessen-Algorithmus erzeugt daraus eine Zielreihenfolge:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;T = (1, 2, 3, …, N)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
indem die Seiten abwechselnd vom Anfang und vom Ende der Dokumentstruktur entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Formal wird für jede Zielposition &amp;lt;code&amp;gt;k&amp;lt;/code&amp;gt; mit &amp;lt;code&amp;gt;1 ≤ k ≤ N&amp;lt;/code&amp;gt; die zugehörige Eingabeseite &amp;lt;code&amp;gt;f(k)&amp;lt;/code&amp;gt; wie folgt bestimmt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
f(k) =&lt;br /&gt;
  N - ⌊(k-1)/2⌋    falls k ≡ 1 (mod 4)&lt;br /&gt;
  1 + ⌊(k-2)/2⌋    falls k ≡ 2 (mod 4)&lt;br /&gt;
  1 + ⌊(k-3)/2⌋    falls k ≡ 3 (mod 4)&lt;br /&gt;
  N - ⌊(k-4)/2⌋    falls k ≡ 0 (mod 4)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Abbildung stellt sicher, dass die Seiten paarweise von aussen nach innen korrekt angeordnet werden.&lt;br /&gt;
&lt;br /&gt;
== Anwendungsbeispiel ==&lt;br /&gt;
Eine Broschüre mit 8 physischen Seiten wird geöffnet (Bostitch entfernt) und über einen Durchlaufscanner digitalisiert.&lt;br /&gt;
&lt;br /&gt;
=== Scan-Ergebnis ===&lt;br /&gt;
Der Scanner erfasst aufgeklappte Doppelseiten, welche anschliessend in zwei Bilder aufgetrennt werden:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Gescannte Seite !! Bild 1 !! Bild 2&lt;br /&gt;
|-&lt;br /&gt;
| Scan 1 || Seite 8 || Seite 1&lt;br /&gt;
|-&lt;br /&gt;
| Scan 2 || Seite 2 || Seite 7&lt;br /&gt;
|-&lt;br /&gt;
| Scan 3 || Seite 6 || Seite 3&lt;br /&gt;
|-&lt;br /&gt;
| Scan 4 || Seite 4 || Seite 5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die daraus resultierende Bildliste (Eingabe für den Serverjob) lautet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;(8, 1, 2, 7, 6, 3, 4, 5)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Produktionsauftr%C3%A4ge&amp;diff=9398</id>
		<title>Produktionsaufträge</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Produktionsauftr%C3%A4ge&amp;diff=9398"/>
		<updated>2026-01-07T10:20:50Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3576: Wiki aktualisiert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Fenstername:&lt;br /&gt;
  &#039;&#039;&#039;FHK_Maske1&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Kopfdaten eines Produktionsaufträge ==&lt;br /&gt;
&lt;br /&gt;
[[File:Kopfdaten.png|1000px|thumb|none|Tab 1 - Kopfdaten]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Taste Duplizieren ===&lt;br /&gt;
&lt;br /&gt;
Ermöglicht das duplizieren eines Auftrages und seiner Elemente. &lt;br /&gt;
&lt;br /&gt;
*Ein duplizierter Auftrag behält den Namen seiner Vorlage mit dem Suffix &amp;quot; - (Kopie)&amp;quot; und erhält den Auftragsstatus &amp;quot;offen&amp;quot;.&lt;br /&gt;
*Duplizierte Produktionsschritte erhalten alle den HZ Status &amp;quot;gestoppt&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zu duplizerenden Elemente des Auftrages müssen dazu entsprechend ausgewählt werden.&lt;br /&gt;
&lt;br /&gt;
[[File:dupliAuswahl.png]]&lt;br /&gt;
&lt;br /&gt;
Da es in einem Auftrag zu den Produktionsschritten Einstellungen geben kann, welche Auftragsspezifisch sind (Speicherpfade, Auslieferpfade, Dokumentenpfade, Internet Adressen, Benutzernamen und Kennwörter, usw.),&lt;br /&gt;
muss bei der Auswahl &amp;quot;Absolute Referenzen&amp;quot; duplizieren besonders darauf geachtet werden, keine falschen Angaben zu übernehmen. Alle Konfigurationen sollten anschliessend entsprechend sorgfältig überprüft werden.&lt;br /&gt;
&lt;br /&gt;
Zu den Feldern für &amp;quot;Absolute Referenzen&amp;quot; gehören:&lt;br /&gt;
&lt;br /&gt;
 HZ_OUTPUTPFAD&lt;br /&gt;
 HZ_INPUTPFAD&lt;br /&gt;
 HZ_USERNAME&lt;br /&gt;
 HZ_ZIELERSATZPFAD&lt;br /&gt;
 HZ_METATEXTFILE&lt;br /&gt;
 HZ_METADATENINPUTFILE&lt;br /&gt;
 HZ_POOLPFAD&lt;br /&gt;
 HZ_HOST&lt;br /&gt;
&lt;br /&gt;
== Produktionsschritte ==&lt;br /&gt;
&lt;br /&gt;
Erstellung und Basiskonfiguration der verfügbaren Arbeitsschritte.&lt;br /&gt;
&lt;br /&gt;
Herkömmliche Tasten auf der rechte Seite wie &#039;&#039;&#039;Liste&#039;&#039;&#039; (Übersicht aller Produktionsaufträge/HK), &#039;&#039;&#039;Leistungen&#039;&#039;&#039; (ausgeführte Arbeiten eines Arbeitnehmers/AN innerhalb eines Produktionsauftrages/HK), &#039;&#039;&#039;Begleitlieferschein&#039;&#039;&#039;, &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Produktionsauftragsübersicht&#039;&#039;&#039; (Report aller Einzelheiten zu einem Produktionsauftrag/HK), &#039;&#039;&#039;Produktionsschritte ordnen&#039;&#039;&#039; (Planung des Arbeitsablaufes).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Produktionsschritte.png|1000px|thumb|none|Tab 2 - Produktionsschritte]]&lt;br /&gt;
&lt;br /&gt;
====Generell====&lt;br /&gt;
&lt;br /&gt;
*Serverjob: Auswahl eines Client- oder Serverseitigen Arbeitsschrittes. (Client = manuelle Verarbeitung im Helper, Server = automatische Verarbeitung durch HLI Server)&lt;br /&gt;
*Bezeichnung: Wörtliche Bezeichnung des Schrittes entsprechend der Workflowplanung&lt;br /&gt;
*Unterordner: Speicherpfad für Daten im Hauptspeicherpfad des Auftrages&lt;br /&gt;
*Alternative Quellen: Alternative Quellen werden berücksichtig, wenn die Objekte am Originalpfad nicht mehr vorhanden sind. Dabei können beliebig viele Zeilen konfiguriert werden. Es wird aber der erste existierende Pfad verwendet.&lt;br /&gt;
&lt;br /&gt;
Format: &amp;lt;zuErsetzendenTeilDesOriginalPfad&amp;gt;*&amp;lt;AlternativerPfad&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel: Die benötigte Datei ist unter dem Originalpfad &amp;quot;O:\11_Helper\Produktion\Bodenforschung\Rename\011.tif&amp;quot; nicht mehr vorhanden. Über alternative Dateipfade soll unter &amp;quot;C:\Deleatur\Rename\011.tif&amp;quot; oder &amp;quot;E:\Deleatur\Rename\011.tif&amp;quot; nach den fehlenden Dateien gesucht werden.&lt;br /&gt;
&lt;br /&gt;
 O:\11_Helper\Produktion\Bodenforschung\*C:\Deleatur\&lt;br /&gt;
 O:\11_Helper\Produktion\Bodenforschung\*E:\Deleatur\&lt;br /&gt;
&lt;br /&gt;
====Zertifikate====&lt;br /&gt;
&lt;br /&gt;
====Daten====&lt;br /&gt;
&lt;br /&gt;
Grundsätzlich nur für Clientarbeitsschritte zu konfigurieren!&lt;br /&gt;
&lt;br /&gt;
*Daten auf Server Speichern: Verhalten für verarbeitete Daten. Wenn die Daten (Dateien!) am Schritt nicht verändert werden, müssen diese in der Regel auch nicht nochmals gespeichert werden.&lt;br /&gt;
*Daten vom Server holen: Lädt die Dateien in den lokalen Arbeitsordner der ausführenden Arbeitsstation. (Dateien des letzten Arbeitsschrittes gelten damit als Basis für diesen Arbeitsschritt)&lt;br /&gt;
*Metadaten erfassen:&lt;br /&gt;
*Fehlermarkierung erlaubt: Ermöglich das markieren eines Objektes bei der manuellen Verarbeitung, wenn nach dem Abschliessen des Objektes eine Unsicherheit über die korrekte Verarbeitung besteht. Objekte können somit aufgefangen werden und fliessen nicht automatisch zum nächsten Arbeitsschritt weiter.&lt;br /&gt;
*Beenden nicht erlaubt: Erzwingt die abschliessende Bearbeitung eines bereits angefangenen Objektes an einem Arbeitsschritt. Ein Objekt kann somit nicht pausiert werden und muss vollständig bearbeitet werden.&lt;br /&gt;
*Zuweiseverhalten beim Beenden: &lt;br /&gt;
 Zuweisung aufheben = Ein beendetes Objekt bleibt nicht derjenige Person, welche es bearbeitet hat, zugewiesen. Es fliesst zurück in den Objektpool des Arbeitsschrittes und muss/kann danach neu zugewiesen werden. &lt;br /&gt;
 Zuweisung beibehalten = Ein beendetes Objekt bleibt der Person zugewiesen welche es bearbeitet hat.&lt;br /&gt;
&lt;br /&gt;
====Sonstiges====&lt;br /&gt;
&lt;br /&gt;
*Benötigter Machinentyp: Erlaubt eine Einschränkung der für den Arbeitsschritt in frage kommenden Arbeitsstationen&lt;br /&gt;
*Untersystemtyp: Essentielles Feld für die indivuelle Konfiguration des verwendeten Arbeitsfensters. Ermöglicht die Auswahl von Auftrags- oder Arbeitschrittbezogenen Modulen im Arbeitsfenster.&lt;br /&gt;
*Arbeitsschritt für Unterobjekte:&lt;br /&gt;
*Serverjob Version: Ermöglicht die Auswahl von versionsabhängigen Verarbeitungsalgorythmen oder von unterschiedlichen drittanbieter Komponenten in den automatisierten Serverarbeitsschritten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schalter Produktionsschritte Ordnen===&lt;br /&gt;
&lt;br /&gt;
Öffnet das Fenster über welches der Workflow des Projektes sowie die Detailkonfiguration der einzelnen erstellen Arbeitsschritte verwaltet werden kann.&lt;br /&gt;
&lt;br /&gt;
[[File:KoordinationArbeitsschritte.png|1000px|none|]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Löschen einer Verbindung&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Um eine Verbindung mit einem Arbeitsschritt zu löschen, klicken Sie mit Ctrl + Klick auf den jeweiligen Startbutton.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Mehrere Arbeitsschritte selektieren / deselektieren&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Um mehrere Arbeitsschritte zu selektieren nutzen Sie Shift + Klick. Um einen bestimmten Schritt zu deselektieren können Sie Shift + Rechtsklick verwenden.&lt;br /&gt;
&lt;br /&gt;
==Objekttypen==&lt;br /&gt;
&lt;br /&gt;
Ermöglicht die Konfiguration der Typen und von zugehörigen Attributen (Metadaten) für die zur verarbeitung vorgesehenen Objekte.&lt;br /&gt;
&lt;br /&gt;
[[File:Objekttypen.png|1000px|thumb|none|Tab 3 - Objekttypen]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Objekttypen/DY&#039;&#039;&#039; sowie &#039;&#039;&#039;Attributen/AT&#039;&#039;&#039; dienen der genaueren Beschreibung eines Objektes. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
*&#039;&#039;&#039;Objekttyp&#039;&#039;&#039;: Bilder&lt;br /&gt;
*&#039;&#039;&#039;Attribute&#039;&#039;&#039;: Format, Erstellungsdatum&lt;br /&gt;
&lt;br /&gt;
Der Benutzer hat die Möglichkeit seine zuvor erstellten &#039;&#039;&#039;Vorlagen&#039;&#039;&#039; im Fenster Vorlagen Objekttypen/FDY_ModSpot per Knopfdruck am unteren linken Ende der Objekttypenliste/DY einzufügen. Nähere Informationen dazu in einem anderen Kapitel.&lt;br /&gt;
&lt;br /&gt;
Es ist möglich für jeden Objekttyp &amp;quot;Interessante&amp;quot; Formate, Umfänge oder Kategorieren zu definieren. Mehr Informationen dazu finden Sie unter [[Formate definieren]]&lt;br /&gt;
&lt;br /&gt;
===Attributswerte (Schalter - Werte Anzeigen)===&lt;br /&gt;
&lt;br /&gt;
Ermöglicht eine rasche Übersicht und die Bearbeitung von bereits verarbeiteten Objekte und ihren zugehörigen Attributswerten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Attributwerte.png|1000px|thumb|none|]]&lt;br /&gt;
&lt;br /&gt;
==Einlagerung==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Tab4.jpg|1000px|thumb|none|Tab 4 - Einlagerung]]&lt;br /&gt;
&lt;br /&gt;
==Anleitung==&lt;br /&gt;
&lt;br /&gt;
[[File:Anleitung.png|1000px|thumb|none|Tab 5 - Anleitung]]&lt;br /&gt;
&lt;br /&gt;
Ermöglicht das erstellen einer Arbeitsanleitung zu einem Produktionsschritt&lt;br /&gt;
&lt;br /&gt;
==Diverses - Automatisches zuweisen von Objekten==&lt;br /&gt;
&lt;br /&gt;
Ermöglicht das automatische Zuweisen von Objekten zu Angestellten. Eine Einschränkung auf einen bestimmten Objekttyp (Siehe Objekttypen) ist dabei möglich.&lt;br /&gt;
&lt;br /&gt;
Je Arbeitschritt ist für jeden Angestellten ein Eintrag zu erstellen mit der Anzahl an Objekten welche maximal immer zugewiesen werden sollen.&lt;br /&gt;
&lt;br /&gt;
Angestellte werden über den Suchkürzel ausgewählt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Diveres.png|1000px|thumb|none|Tab 6 - Diverses]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Diverses - Vier Augen Prinzip==&lt;br /&gt;
&lt;br /&gt;
Dies ist eine Qualitätssicherungsfunktion.&lt;br /&gt;
&lt;br /&gt;
Sie ermöglicht das Sperren von Arbeitsschritten, bzw. unterbindet das öffnen von Objekten an diesen Schritten, in Abhängigkeit von bereits zuvor ausgeführten Arbeitschritten der gleichen Person am gleichen Objekt.&lt;br /&gt;
&lt;br /&gt;
Damit kann gewährleistet werden, dass in einem Arbeitsprozess ein Objekt nicht an zwei unterschiedlichen Arbeitsschritten von einer einzigen Person bearbeitet werden kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bsp.: Eine Person welche einen kontrollieren Schritt ausführt, darf an diesem Schritt keine Objekte kontrollieren, welche zuvor von ihr selbst an einem oder mehreren anderen Schritten erzeugt oder bearbeitet wurden.&lt;br /&gt;
&lt;br /&gt;
Über das Dropdownmenü den gewünschten Arbeitsschritt wählen, bei welchem der Bearbeitungsverlauf von Objekten betrachtet werden soll. z.B.: 6 - Kontrolle&lt;br /&gt;
&lt;br /&gt;
[[Datei:4ap_kontrolle.png]]&lt;br /&gt;
&lt;br /&gt;
In der Checkboxliste darunter nun diejenigen Schritte auswählen, welche als Ausschlusskriterium gelten. z.B.: 4 - Scannen der Kleinbild-Dias..&lt;br /&gt;
&lt;br /&gt;
[[Datei:4ap_checklist.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Versucht nun eine Person, welche am Schritt 4 ein Dia gescannt hat, das zugehörige Objekte am Schritt 6 zu kontrollieren, erscheint eine Fehlermeldung und das öffnen des Objektes zur bearbeitung wird abgebrochen.&lt;br /&gt;
&lt;br /&gt;
==Word==&lt;br /&gt;
&lt;br /&gt;
[[File:word.png|1000px|thumb|none|Tab 7 - Word]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflow]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Filetest&amp;diff=9383</id>
		<title>Filetest</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Filetest&amp;diff=9383"/>
		<updated>2025-11-07T09:35:26Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3554: Wiki für den neuen Filtest erstellt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  1526&lt;br /&gt;
&lt;br /&gt;
  1822&lt;br /&gt;
;Systemtyp: &lt;br /&gt;
  18&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
Besteht aus einem Serverjob OJOHZDOFiletest. Überprüft die Files auf ihre Richtigkeit. Das Ergebnis (0/1) kann in einem Attribut gespeichert werden. Falls ein Test fehlschlägt geht das Objekt zu zum roten Ausgang und im Fehlertext steht, welche Bedingung(en) nicht erfüllt wurde(n).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Grundsätzlich sind hier keine Formeln für die Werte möglich, mit Ausnahme:&#039;&#039;&#039; &#039;&#039;FileAnzahl&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Konfiguration FileAnzahl===&lt;br /&gt;
Bei diesem Test werden die &#039;&#039;&#039;Dateien und Ordner&#039;&#039;&#039; im auf oberster Ebene im Objektordner gezählt. Die Dateien in (Unter-)Ordnern zählen nicht. Der Ordner &#039;Hilfsobjekte&#039; zählt auch.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Zugriff auf Metadaten des Objektes, bzw. das einsetzen von Formel sind für diesen Test erlaubt.&#039;&#039;&#039; &#039;&#039;Das Metadatum ist wie üblich in eckigen Klammern zu nennen: [MetadatumMitAnzahl]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Konfiguration FileTyp===&lt;br /&gt;
Bei diesem Test wird jedes File im Objektordner mit konfigurierten Filetyp verglichen. Ordner werden (natürlich) nicht verglichen. Files in Unterordnern werden nur getestet, wenn &#039;Rekursiv&#039; angekreuzt ist. &lt;br /&gt;
&lt;br /&gt;
===Konfiguration BildformatXY===&lt;br /&gt;
Bei diesem Test können beide Seiten des Bildformats (X und Y) berücksichtigt werden.&lt;br /&gt;
*Operator Codes können sein (&amp;gt;, *&amp;gt;, &amp;gt;&amp;gt;, *&amp;gt;&amp;gt;) Bzw. die Varianten für kleiner (&amp;lt;) und gleich (=)&lt;br /&gt;
*&amp;gt;,= wenn eine Seite grösser/gleich als ihr entsprechender Maximalwert (xi &amp;gt; xs) | (yi &amp;gt; ys)&lt;br /&gt;
*&amp;gt;&amp;gt;,== wenn beide Seiten grösser / gleich wie der entsprechende Maximalwert (xi &amp;gt; xs) &amp;amp; (yi &amp;gt; ys)&lt;br /&gt;
* *&amp;gt;, *= wenn mindestens eine beliebige Seite grösser / gleich ist wie ein beliebiger Maximalwert&lt;br /&gt;
* *&amp;gt;&amp;gt;, *== wenn je beide Seiten grösser / gleich wie ein beliebiger Maximalwert sind (Bildausrichtung gleich oder gedreht)&lt;br /&gt;
Der Vergleichswert wird geschrieben: 2000x3000&lt;br /&gt;
&lt;br /&gt;
===Konfiguration Farbraum===&lt;br /&gt;
Bei diesem Test wird der Farbraum aus dem File gelesen. Typische Werte sind &#039;Gray&#039; oder &#039;sRGB&#039;. Bitte achten Sie auf Grosskleinschreibung.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration Positions SW Histogramm ===&lt;br /&gt;
Bei diesem Test wird ein Histogramm in einem PDF / Bild generiert basierend auf einer bestimmten Position sowie einem Grössenbereich.&lt;br /&gt;
Grundsätzlich wird immer von links oben aus gerechnet.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
1. Parameter = Seite - zB 4 (Wird nur bei PDF&#039;s verwendet)&amp;lt;br&amp;gt;&lt;br /&gt;
2. Parameter = Position X - zB 250 oder -150 (Bei Bildern in Pixel, bei PDF&#039;s in mm / Negative Zahlen werden von Rechts statt Links aus gerechnet)&amp;lt;br&amp;gt;&lt;br /&gt;
3. Parameter = Position Y - zB 300 oder - 200 (Bei Bildern in Pixel, bei PDF&#039;s in mm / Negative Zahlen werden von Unten statt Oben aus gerechnet)&amp;lt;br&amp;gt;&lt;br /&gt;
4. Parameter = Breite - zB 500 oder 25 % (Entweder Prozentangabe oder bei Bildern in Pixel, bei PDF&#039;s in mm)&amp;lt;br&amp;gt;&lt;br /&gt;
5. Parameter = Höhe - zB 200 oder 15 % (Entweder Prozentangabe oder bei Bildern in Pixel, bei PDF&#039;s in mm)&amp;lt;br&amp;gt;&lt;br /&gt;
6. Parameter = Helligkeitsgrenzwert - zB 150 (Werte von 0 - 255, wobei 0=Schwarz / 255 = Weiss)&amp;lt;br&amp;gt;&lt;br /&gt;
7. Parameter = Prozent - zB 35% (Wie viel Prozent der Pixel müssen über oder unter der angegeben Helligkeit sein)&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Hier ein komplettes Beispiel: &amp;quot;1,100,-150,140,5%,200,30%&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
*Es wird Seite 1 gemessen (falls es um ein PDF geht)&lt;br /&gt;
*Es wird der folgende Bildausschnitt genommen: Annahme das Bild ist 1000x500px gross&lt;br /&gt;
** Linke obere Ecke: 100/350 px. (350=500-150)&lt;br /&gt;
** Grösse des Ausschnitts: 140x25 px. (25=5% von 500)&lt;br /&gt;
** Rechte untere Ecke: 240/375 px.&lt;br /&gt;
*Es wird folgende Formel evaluiert:&lt;br /&gt;
  (Pixelheller (als Grauwert 200) / TotaleAnzahlPixel) &amp;gt; oder &amp;lt; Prozent (30%).&lt;br /&gt;
Es werden also immer die helleren Pixel als der Helligkeitsgrenzwert gezählt und durch die totale Anzahl Pixel geteilt. Das Ergebnis wird mit dem Prozentsatz verglichen.&lt;br /&gt;
Falls ein Wert nicht angegeben werden soll muss das Komma dennoch da stehen. Beispiel ohne die Angabe der Seite: &amp;quot;,100,-150,140,5%,200,30%&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
==== Beispiele Bildausschnitt====&lt;br /&gt;
* Das ganze Bild (Seite 1) soll gemessen werden: &amp;quot;1,1,1,100%,100%...&amp;quot;&lt;br /&gt;
* Links oben in der Ecke soll ein Quadrat von 100px gemessen werden: &amp;quot;1,1,1,100,100...&amp;quot;&lt;br /&gt;
==== Beispiele Helligkeit====&lt;br /&gt;
* Es darf fast keine (fast) schwarzen Pixel haben: &amp;gt; &amp;quot;...20, 98%&amp;quot; -&amp;gt; mehr als 98% der Pixel sollen heller sein als fast schwarz (Grauwert 20)&lt;br /&gt;
* Es soll fast ganz weiss sein: &amp;gt; &amp;quot;...240, 99%&amp;quot; -&amp;gt; 99% der Pixel sollen heller als der Grauwert 240 sein (fast weiss)&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration Ist Extrem ===&lt;br /&gt;
Bei diesem Test wird jedes DO geprüft ob es nach der konfigurierten Weise extrem ist.&lt;br /&gt;
&lt;br /&gt;
1. Parameter = Sortierfeld - Dieser Wert wird aufs &amp;quot;Extrem sein&amp;quot; geprüft. Muss ein AT-Name sein&amp;lt;br&amp;gt;&lt;br /&gt;
2. Parameter = Selektionsfeld - Es werden nur DOs berücksichtig die den gleichen Wert im Selektionsfeld haben wie das DO welches gerade angeschaut wird. Muss ein AT-Name sein. Falls leer wird DO_DO_SEQ automatisch verwendet.&amp;lt;br&amp;gt;&lt;br /&gt;
3. Parameter = Menge - Ab wann wird ein DO als Extrem beachtet? zB. 10&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Hier ein komplettes Beispiel: &amp;quot;seitenanzahl,pdfname,10&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
Ist das DO in den Top 10 mit den Seitenzahlen verglichen mit allen DOs welche denselben PDF Namen haben?&lt;br /&gt;
&lt;br /&gt;
===Konfiguration Pixeltiefe pro Kanal===&lt;br /&gt;
Bei diesem Test wird die Anzahl Pixel pro Kanal aus dem File gelesen. Typische Werte sind 8 oder 16.&lt;br /&gt;
&lt;br /&gt;
===Konfiguration ICC Profile===&lt;br /&gt;
Bei diesem Test wird aus dem File die Zeile icc:description gefiltert und der Text danach herausgelesen. Ein typischer Wert ist &#039;Adobe RGB (1998)&#039;.&lt;br /&gt;
&lt;br /&gt;
Sie können das Feld bei einem Bild auch auslesen:&lt;br /&gt;
  identify -verbose &amp;quot;Pfad zum Bild&amp;quot;&lt;br /&gt;
Suchen Sie nach der Zeile &#039;icc:description&#039;&lt;br /&gt;
&lt;br /&gt;
===Dateigrösse===&lt;br /&gt;
&lt;br /&gt;
Bei diesem Test wird eine Dateigrösse in Bytes geprüft.&lt;br /&gt;
&lt;br /&gt;
Operator Codes können sein (&amp;gt;,&amp;lt;).&lt;br /&gt;
&lt;br /&gt;
===SeitenAnzahl===&lt;br /&gt;
&lt;br /&gt;
Bei diese Test wird die Anzahl Seiten in einem PDF oder TIFF Dokument geprüft. &lt;br /&gt;
&lt;br /&gt;
Operator Codes können sein (&amp;gt;,&amp;lt;,=,&amp;lt;&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===Anzahl Barcodes in Ordner===&lt;br /&gt;
&lt;br /&gt;
Bei diesem Test wir die Anzahl Barcodes eines bestimmten Typs mit einem bestimmten Wert im gesamten Ordner getestet.&lt;br /&gt;
&lt;br /&gt;
Operator Codes können sein (&amp;gt;,&amp;lt;,=,&amp;lt;&amp;gt;,&amp;lt;=, &amp;gt;=).&lt;br /&gt;
&lt;br /&gt;
Wertkonfiguration: Anzahl Barcodes,Barcodewert,Barcodetyp&lt;br /&gt;
&lt;br /&gt;
Beispiel: 2,ABC1234,Code 39&lt;br /&gt;
&lt;br /&gt;
===Konfiguration Pixeltiefe pro Kanal===&lt;br /&gt;
Bei diesem Test wird die Anzahl Pixel pro Kanal aus dem File gelesen. Typische Werte sind 8 oder 16.&lt;br /&gt;
&lt;br /&gt;
==Allgemeine Metadaten von Bildformaten==&lt;br /&gt;
&lt;br /&gt;
Für die unten folgenden Konfigurationen kann für die gesuchten Werte auf diese Auflistungen von TAG Namen zurückgegriffen werden: &lt;br /&gt;
&lt;br /&gt;
[https://www.exiftool.org/TagNames/ TAG Übersicht]&lt;br /&gt;
&lt;br /&gt;
[https://www.exiftool.org/TagNames/EXIF.html EXIF Tags]&lt;br /&gt;
&lt;br /&gt;
[https://www.exiftool.org/TagNames/IPTC.html IPTC Tags]&lt;br /&gt;
&lt;br /&gt;
[https://www.exiftool.org/TagNames/XMP.html XMP Tags]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Suche nach leeren Tags&#039;&#039;&#039;&lt;br /&gt;
 &lt;br /&gt;
Falls nach leeren, bzw. fehlenden Werten gesucht werden soll, dann ist der Wertebereicht nach dem Komma leer zu lassen.&lt;br /&gt;
&lt;br /&gt;
Bsp.: Kein Änderungsdatum vorhanden&lt;br /&gt;
&lt;br /&gt;
[[Datei:Metadatum Datum leer.png]] &lt;br /&gt;
&lt;br /&gt;
===Konfiguration Metadatum Text===&lt;br /&gt;
&lt;br /&gt;
Bei diesem Test wird ein TAG mit Textinhalt verglichen.&lt;br /&gt;
&lt;br /&gt;
Operator Codes können sein (=, &amp;lt;&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
Bsp.: Gesucht wird der Hersteller des Aufnahmegerätes. Der entsprechende TAG heisst &#039;Make&#039;. Der gesuchte Wert soll auf &#039;Canon&#039; lauten.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Metadatum Text.png]]&lt;br /&gt;
&lt;br /&gt;
===Konfiguration Metadatum Zahl===&lt;br /&gt;
&lt;br /&gt;
Bei diesem Test wird ein TAG mit Zahleninhalt verglichen.&lt;br /&gt;
&lt;br /&gt;
Operator Codes können sein (=, &amp;lt;&amp;gt;, &amp;gt;, &amp;gt;=, &amp;lt;, &amp;lt;=)&lt;br /&gt;
&lt;br /&gt;
Bsp.: Gesucht wird nach der X Auflösung des Bildes. Der entsprechende TAG heisst &#039;XResolution&#039;. Der gesuchte Wert soll grösser oder gleich 3500 sein.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Metadatum Zahl.png]]&lt;br /&gt;
&lt;br /&gt;
===Konfiguration Metadatum Datum===&lt;br /&gt;
&lt;br /&gt;
Bei diesem Test wird ein TAG mit Datumsinhalt verglichen.&lt;br /&gt;
&lt;br /&gt;
Operator Codes können sein (=, &amp;lt;&amp;gt;, &amp;gt;, &amp;gt;=, &amp;lt;, &amp;lt;=)&lt;br /&gt;
&lt;br /&gt;
Bsp.: Gesucht wird dem Änderungsdatum. Der entsprechende TAG heisst &#039;DateModify&#039;. Der gesuchte Wert soll nach dem 23.03.2021 08:05:14 liegen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Metadatum Datum.png]]&lt;br /&gt;
&lt;br /&gt;
==Dateien auch in den Unterordnern prüfen==&lt;br /&gt;
&lt;br /&gt;
Soll auch in Unterordner geprüft werden, ist folgende Checkbox zu aktivieren:&lt;br /&gt;
&lt;br /&gt;
[[File:filetest_rekursiv.png]]&lt;br /&gt;
&lt;br /&gt;
Der Filetest beim Abschliessen eines clientseitigen Arbeitsschrittes ist nicht rekursiv.&lt;br /&gt;
&lt;br /&gt;
== Dateinamen auf Regex überprüfen ==&lt;br /&gt;
Sie können den Dateinamen mithilfe eines Regex überprüfen lassen.&lt;br /&gt;
Wählen Sie dazu die Kondition &amp;quot;Dateiname&amp;quot; und den Operator &amp;quot;entspricht Regex&amp;quot;, dann &#039;&#039;&#039;muss jedes File&#039;&#039;&#039; im Objektordner dem Regex entsprechen.&lt;br /&gt;
Wenn Sie &amp;quot;entspricht nicht Regex&amp;quot; wählen, dann &#039;&#039;&#039;darf kein File&#039;&#039;&#039; dem Regex entsprechen.&lt;br /&gt;
&lt;br /&gt;
Tool um Regex zu schreiben: https://regex101.com&lt;br /&gt;
&lt;br /&gt;
[[Datei:Filetest regexmatching.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Barcodes finden==&lt;br /&gt;
&lt;br /&gt;
Ermittelt, ob die Seiten einen Barcode besitzen. Ein bestimmer Suchwert für den Inhalt des Barcodes kann ebenfalls als Einschränkung mitgegeben werden.&lt;br /&gt;
&lt;br /&gt;
Kann alle Seiten, oder nur die geraden, oder nur die ungeraden prüfen. Wenn wir hier von Seiten sprechen, dann sind damit einzelne Dateien gemeint, welche in der Regel eine einzelne Seite darstellen. Die Reihenfolge der nach Namen sortierten Dateien im Dateisystem legt dabei die Seitenzahl fest. Die erste Datei - Sortiernummer 1 - entspricht demnach einer ungeraden Seite. Datei achte Datei - Sortiernummer 8 - einer geraden Seite.&lt;br /&gt;
&lt;br /&gt;
Unterstüzte Dateitypen - alle gängigen Bildformate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Attribut:&#039;&#039;&#039; SeiteHatBarcodes&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Operator Code:&#039;&#039;&#039;  ( = )&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wert:&#039;&#039;&#039; A/U/G/[Zahl]&#039;&#039;&#039;,&#039;&#039;&#039;Barcodeinhalt,Barcodetyp&lt;br /&gt;
&lt;br /&gt;
*A = alle Seiten (es muss auf allen Seiten einen Barcode haben)&lt;br /&gt;
*U = ungerade Seiten (es darf nur auf ungeraden Seiten barcodes haben. Es muss aber nicht auf allen ungeraden Seiten Barcodes haben)&lt;br /&gt;
*G = gerade Seiten (es darf nur auf geraden Seiten barcodes haben. Es muss aber nicht auf allen geraden Seiten Barcodes haben)&lt;br /&gt;
*[Zahl] = zB. 5 =&amp;gt; Hat es auf der 5. Seite einen Barcode?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bsp.:&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
1) Suche auf ungeraden Seiten nach einem Barcode: &#039;&#039;&#039;Wert = 1&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
2) Suche auf geraden Seiten (2) nach einem Barcode mit dem Wert 0783A-123: &#039;&#039;&#039;Wert = 2,0783A-123&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Merke:&#039;&#039;&#039; Die Suche nach einem Wert funktioniert aktuell nur für den ersten gefundenen Barcode! Wenn es mehrere Barcodes auf der Seite gibt, wird jeweils der erste Ausgewertet.&lt;br /&gt;
&lt;br /&gt;
Falls eine Zahl angegeben wird, kann der Barcodetyp definiert werden. In der anderen Fällen ist der Parameter nicht implementiert. Ebenfalls kann der Wert ein Regex sein, sofern eine Zahl definiert ist.&lt;br /&gt;
&lt;br /&gt;
==Unsichtbare Dateien==&lt;br /&gt;
File test prüft auch unsichtbare/geschützte Systemdateien wie Thumps.db. Dies ist Absicht, damit verhindert werden kann, dass diese Dateien weiter im Workflow gehen. Damit Sie die unsichtbaren/geschützen Systemdateien sehen (und ggf. löschen) können, müssen Sie sie in Windows sichtbar machen:&lt;br /&gt;
* Für geschützte Systemdateien: Deselektieren Sie &#039;Ordneroptionen: Ansicht: Erweiterte Einstellungen: Geschützte Systemdateien ausblenden&#039;&lt;br /&gt;
* Für unsichtbare Dateien: Im Befehlsband: &#039;Ansicht&#039;, &#039;unsichtbare Dateien&#039;&lt;br /&gt;
&lt;br /&gt;
==Essentielle Felder==&lt;br /&gt;
  AR_FILETEST, HZ_FILETEST   &#039;&#039;Code kTab Attribut kTab Operator kTab Wert(e) kCR&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  HZ_TESTERGEBNIS&lt;br /&gt;
&lt;br /&gt;
  HZ_FILEVERHALTEN&lt;br /&gt;
&lt;br /&gt;
==Pane im Produktionsauftrag (FHK_Maske)==&lt;br /&gt;
&lt;br /&gt;
[[File:0.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Generische_Produktionsauftragsauswertung&amp;diff=9377</id>
		<title>Generische Produktionsauftragsauswertung</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Generische_Produktionsauftragsauswertung&amp;diff=9377"/>
		<updated>2025-10-29T09:15:28Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3491: Doku für Blatt 8&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  3155&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
Die generische Produktionsauftragsauswertung ist eine Excelauswertung mit vielen Informationen über verarbeitete Stückzahlen, Arbeitsstunden, Angestellte und weiteres. Diese Auswertung kann für jeden Produktionsauftrag in einer beliebigen Zeitspanne generiert werden. Navigieren Sie dazu in die Produktionsauftragsmaske, wählen Sie einen Produktionsauftrag aus und klicken Sie auf den Button &amp;quot;Auswertung generieren&amp;quot;. Dabei können Sie aus 2 verschiedenen Modi auswählen. Modus 1 wertet alle Objekte in einem Datumsbereich aus, wobei Modus 2 alle Objekte einer Tranche auswertet.&lt;br /&gt;
&lt;br /&gt;
==Arbeitsblätter==&lt;br /&gt;
Die Arbeitsblätter der Vorlage sind nicht fix definiert. Folgende anpassen können in der Vorlage getätigt werden:&lt;br /&gt;
- Namen der Blätter kann angepasst werden&lt;br /&gt;
- Platzhalten können beliebig verschoben werden (es kann auch mehrmals den gleichen Platzhalter im Dokument haben)&lt;br /&gt;
- Blätter können gelöscht werden&lt;br /&gt;
- Die Reihenfolge der Arbeitsblätter kann verändert werden&lt;br /&gt;
&lt;br /&gt;
Sie dürfen beliebig viele Datums oder Tranchennamen Platzhalter einfügen. Beachten Sie, dass wenn die Auswertung im Datums Modus ausgeführt wird der Tranchenname Platzhalter durch eine Fehlermeldung ersetzt wird und umgekehrt.&amp;lt;br&amp;gt;&lt;br /&gt;
$DATUM$ wir ersetzt durch &amp;quot;Auswertung vom 21.05.2023 bis 18.09.2023&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
$TRANCHENAME$ wird ersetzt durch &amp;quot;Auswertung der Tranche &#039;Tranche XY&#039;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==Checkliste für reibungslosen Ablauf==&lt;br /&gt;
* Für Blatt 3 müssen passende Umfänge, Kategorien und Formate definiert sein. Mehr dazu [[Formate definieren|hier]]&lt;br /&gt;
* Für Blatt 5 sollten alle Angestellten welche an diesem Auftrag arbeiten einen aktiven Vertrag haben&lt;br /&gt;
&lt;br /&gt;
==Blatt 1 - Objektanzahlen==&lt;br /&gt;
Auf diesem Blatt werden die Anzahl Objekte, aufgeschlüsselt nach Objekttyp, welche in der Periode am jeweiligen Arbeitsschritt verarbeitet wurden, aufgelistet. Dabei werden Objekte welche mehrmals am gleichen Arbeitsschritt verarbeitet wurden nicht mitgezählt. Jedes Objekt wird also pro Arbeitsschritt nur einmal gezählt.&lt;br /&gt;
&lt;br /&gt;
==Blatt 2 - Objekt / Seitenanzahlen==&lt;br /&gt;
Dieses Blatt dient als weitere Aufschlüsselung der Zahlen auf dem Blatt 1. Folgende Informationen befinden sich auf Blatt 2: Arbeitsschritt, Maschine, Anzahl Objekte Einmalig, Anzahl Objekte Durchlauf, Anzahl Objekte Doppelt, Anzahl Seiten Einmalig, Anzahl Seiten Durchlauf, Anzahl Seiten Doppelt. Grundsätzlich wenden alle Arbeitsschritte welche keine manuellen Leistungen haben auf diesem Blatt ignoriert. Alle anderen Arbeitsschritte welche mindestens ein verarbeitetes Objekt in der Periode aufweisen, werden aufgelistet.&lt;br /&gt;
&lt;br /&gt;
===Informationen zu den Seitenanzahlen===&lt;br /&gt;
Die Anzahl der Seiten von Objekten wird aus einer materialisierten Sicht gelesen. Diese wird nur einmal täglich aktualisiert. Falls Sie also ganz genaue Zahlen wünschen, setzen Sie das Ende der Periode auf gestern. Es wird die Anzahl verrechenbarer Seiten angezeigt; Diese Anzahl stimmt nicht mit den Seitenzahlen aus den Leistungen überein. Wenn eine Seite 3 mal gescannt wird, weil die ersten 2 Versuche ungenügend waren, erhalten wir nur 1 verrechenbare Seite jedoch wird in der Leistung 3 Seiten abgespeichert. Die Seitenanzahlen werden beim Arbeitsschritt [[Files messen|Files Messen]] gemessen. Alle Objekte welche noch nicht gemessen wurden, zeigen sich nicht in den Kennzahlen der Seiten.&lt;br /&gt;
&lt;br /&gt;
===Beschreibungen der Kennzahlen===&lt;br /&gt;
&#039;&#039;&#039;Maschine&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
An welcher Maschine dieser Arbeitsschritt stattfindet. Achtung: Wenn der Maschinentyp des Arbeitsschritts verändert wird, erscheint es rückwirkend so als ob alle Objekte an der neuen Maschine verarbeitet wurden.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Anzahl Objekte Einmalig&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Die Anzahl Objekte welche in der Periode einmalig verarbeitet wurden. Falls ein Objekt mehrmals am gleichen Schritt verarbeitet wurde wird dies hier nicht gezählt.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Anzahl Objekte Durchlauf&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Die Anzahl Objekte welche in der Periode allgemein an diesem Arbeitsschritt verarbeitet wurden. Dabei werden alle Duplikate gezählt.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Anzahl Objekte Doppelt&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Dies ist die Zahl der einmalig verarbeiten Objekte welche vor der Periode bereits einmal an diesem Schritt verarbeitet wurden. Dabei werden keine Duplikate gezählt; d. H. wenn das Objekt X vor der Periode schon 8 mal an diesem Schritt war, zählt dies jedoch nur als 1 doppeltes Objekt.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Anzahl Seiten Einmalig&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Anzahl Seiten welche an diesem Arbeitsschritt verarbeitet wurden. Falls ein Objekt mehrmals am gleichen Schritt verarbeitet wird, werden die Seiten hier nicht doppelt gezählt.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Anzahl Seiten Durchlauf&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Anzahl Seiten welche in der Periode an diesem Arbeitsschritt verarbeitet wurden. Dabei werden alle Duplikate gezählt. Achtung: Die Auswertung weiss nicht wie viele Seiten wirklich doppelt verarbeitet wurden. Sie multipliziert die Anzahl Seiten des Objektes mit der Anzahl der Durchläufe. Beispiel: Ein Objekt mit 50 Seiten wird 3 mal am Arbeitsschritt XY verarbeitet. Anzahl Seiten Einmalig = 50, Anzahl Seiten Durchlauf = 150. Auch wenn der Angestellte beim 3. Durchlauf nur 15 Seiten bearbeitet hat.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Anzahl Seiten Doppelt&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Anzahl Seiten welche vor der aktuellen Periode bereits verarbeitet wurden. Dabei werden keine Duplikate gezählt.&lt;br /&gt;
&lt;br /&gt;
==Blatt 3 - Formate / Umfänge / Kategorien==&lt;br /&gt;
Auf diesem Blatt werden die Anzahl verarbeite Objekte basierend auf den Konfigurierten Formaten, Umfängen und Kategorien, aufgeschlüsselt nach Objekttyp, gelistet. Dabei wird jedes Objekt nur einmal gezählt und alle Duplikate von mehrfacher Verarbeitung ignoriert. Achtung: Auf diesem Blatt sind die Totalanzahlen dargestellt und nicht die verarbeiteten Objekte in der Periode!&lt;br /&gt;
&lt;br /&gt;
==Blatt 4 - Leistungen (h)==&lt;br /&gt;
Auf diesen Arbeitsblatt werden die Anzahl Stunden aus den Leistungen pro Arbeitsschritt und Objekttyp aufgelistet.&lt;br /&gt;
&lt;br /&gt;
==Blatt 5 - Leistungen Angestellte==&lt;br /&gt;
Auf diesen Arbeitsblatt werden die Leistungen der Angestellten genauer aufgeschlüsselt. Folgende Kennzahlen befinden sich auf diesem Blatt: Arbeitsschritt, Objekttyp, Angestellter, Vertragsart, Stunden Total, Anzahl Objekte, Ø Zeit Objekt (h), Anzahl Seiten gemessen, Ø Zeit pro Seite gemessen (h), Geschätzte Dauer pro Objekt (h), Kalkulatorische Kosten. Werte welche undefiniert sind werden mit N/A angegeben. Achten Sie darauf das alle Angestellte einen gültigen laufenden Vertrag haben. Ansonsten können einige Zahlen nicht berechnet werden.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Stunden Total (h)&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Anzahl Stunden welche der Angestellte an diesem Arbeitsschritt in der Periode gearbeitet hat.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Anzahl Objekte&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Die Anzahl der Objekte welche der Angestellte an diesem Arbeitsschritt in der Periode verarbeitet hat.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Ø Zeit Objekt (h)&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Die durchschnittliche Verarbeitungszeit für ein Objekt&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Anzahl Seiten gemessen&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Die Anzahl der gemessenen Seiten aller Objekte welcher der Angestellte verarbeitet hat. Die Messung der Seiten erfolgt beim [[Files messen|Files Messen]]; Falls ein File in mehrere Typen konvertiert wird erscheinen die in dieser Auswertung obwohl der Angestellte nur 1 Seite gescannt hat. Beispiel: Der Angestellte scannt eine Seite (.tif). Danach wird daraus ein PDF, ein JPG und ein PNG generiert und am Schluss wird das Objekt gemessen. Es erscheinen dann 4 Seiten in der Auswertung, obwohl der Angestellte nur eine Seite gescannt hat.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Ø Zeit pro Seite gemessen (h)&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Die durchschnittliche Verarbeitungszeit pro Seite. Diese Zahl berechnet sich mit Stunden Total / Anzahl Seiten gemessen d.h. sollte der Angestellte 60 Seiten gescannt haben und davon 30 doppelt, merken wir das nicht. Ø Zeit pro Seite gemessen (h) kann in machen Fällen grösser sein als Ø Zeit Objekt (h). Dies geschieht wenn Objekte noch nicht gemessen wurden und deswegen 0 Seiten haben.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Geschätzte Dauer pro Objekt (h)&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Die geschätzte Dauer pro Objekt aus der Auftragsplanung.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Kalkulatorische Kosten&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Die kalkulatorischen Kosten der betriebenen Arbeit des Angestellten in der Periode. Der Stundensatz ist in der Vertragsart definiert.&lt;br /&gt;
&lt;br /&gt;
==Blatt 6 - Maschinenstunden==&lt;br /&gt;
Auf diesem Arbeitsblatt wird die Anzahl der gearbeiteten Stunden pro Angestellter und Maschine aufgelistet.&lt;br /&gt;
&lt;br /&gt;
==Blatt 8 - Generisch zur Verrechnung==&lt;br /&gt;
Auf diesem Blatt lassen sich Metadaten und Leistungen von DOs anzeigen. Wichtig: Es werden nur DOs beachtet welche zur Verrechnung bereitstehen. Das bedeutet die DOs müssen am Arbeitsschritt &amp;quot;Letzter Arbeitsschritt&amp;quot; (DY_HZ_SEQ2) verarbeitet worden sein. Dieser lässt sich in der Produktionauftragsmaske unter Objekttypen konfigurieren. Auch im Tranchenmodus werden nur DOs welche zu verrechnen sind aufgelistet.&lt;br /&gt;
&lt;br /&gt;
===Platzhalter===&lt;br /&gt;
Um das Blatt als diesen Typ zu definieren muss irgendwo $ATGENERISCH$ stehen. Dieser Platzhalter wird in der fertigen Auswertung dann gelöscht. Folgende Platzhalter können auf diesem Blatt verwendet werden:&lt;br /&gt;
&lt;br /&gt;
====$START(&#039;[Objekttyp]&#039;)$====&lt;br /&gt;
Dieser Platzhalter markiert den Start der Auswertung. Das heisst 1 Zeile unter diesem Platzhalter startet die Liste der DO-Informationen. Damit wird ebenfalls definiert, welcher Objekttyp in der Auswertung angezeigt werden soll.&lt;br /&gt;
&lt;br /&gt;
Beispiel: $START(&#039;Buch&#039;)$&lt;br /&gt;
&lt;br /&gt;
====$DOMetawert(&#039;[MetadatumName]&#039;)$====&lt;br /&gt;
Dieser Platzhalter zeigt einen Wert eines beliebigen Metadatums des DO an.&lt;br /&gt;
&lt;br /&gt;
Beispiel: $DOMetawert(&#039;Hausnummer&#039;)$ -&amp;gt; wird dann zu zB. 58A&lt;br /&gt;
&lt;br /&gt;
====$DOLSstd(row(&#039;Arbeitsvertragstyp&#039;))$====&lt;br /&gt;
Dieser Platzhalter zeigt den Wert aller gearbeiteter Stunden dieses DO von einer oder mehreren Arbeitsvertragsarten.&lt;br /&gt;
&lt;br /&gt;
Beispiel: $DOLSstd(row(&#039;MOR&#039;))$ -&amp;gt; wird dann zu zB. 1.456&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es können auch mehere Vertragsarten summiert werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel: $DOLSstd(row(&#039;MOR&#039;,&#039;MMR&#039;,&#039;ZIVI&#039;))&lt;br /&gt;
&lt;br /&gt;
====Weitere Platzhalter====&lt;br /&gt;
$DOSEQ$ -&amp;gt; Sequenzschlüssel des DO&lt;br /&gt;
&lt;br /&gt;
$DOSIGNATUR$-&amp;gt; Signatur des DO&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Normaler_Arbeitsschritt&amp;diff=9353</id>
		<title>Normaler Arbeitsschritt</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Normaler_Arbeitsschritt&amp;diff=9353"/>
		<updated>2025-10-13T09:46:15Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3537: HZ_HASTYP zu HZ_FILEVERHALTEN geändert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  2237&lt;br /&gt;
;Systemtyp: &lt;br /&gt;
  0&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
Dieser Arbeitsschritt wird zB fürs Digitalisieren oder andere manuelle Tätigkeiten an Files verwendet. Er legt die Daten des vorherigen Arbeitschrittes eines Objektes in C:\Work\Input und erwartet die Daten nach der manuellen Bearbeitung in C:\Work\Output.&lt;br /&gt;
===Digitalisieren===&lt;br /&gt;
Digitalisieren Sie alles in C:\Work\Output.&lt;br /&gt;
===Manuelle Bearbeitung von Files===&lt;br /&gt;
&lt;br /&gt;
===Leistungen===&lt;br /&gt;
Beim Starten des Schrittes wird Name und Änderungsdatum der Files im Ordner C:\Work\Output in einer Liste gespeichert. Am Beenden wird die Liste mit dem dann aktuellen Inhalt verglichen. Es können folgenden Leistungen vorkommen:&lt;br /&gt;
;Datei, Create: Eine Datei mit diesem Namen existierte beim Start noch nicht.&lt;br /&gt;
;Datei, Update: Eine Datei mit diesem Namen existierte beim Start schon, hat am Ende aber ein anderes Änderungsdatum.&lt;br /&gt;
;Datei, Delete: Eine Datei mit diesem Namen existierte beim Start, fehlt aber am Ende.&lt;br /&gt;
;Sonderobjekte: Ein Sonderobjekt wurde erstellt.&lt;br /&gt;
&lt;br /&gt;
=Konfiguration=&lt;br /&gt;
&lt;br /&gt;
* Generell&lt;br /&gt;
&lt;br /&gt;
* File Test, Die Filetests sind hier nicht rekursiv. Es werden nur die Files auf der obersten Ebene im Arbeitsordner kontrolliert. Die Filetests können bei &amp;quot;Feierabend&amp;quot; ausgestellt werden.&lt;br /&gt;
&lt;br /&gt;
* Metadaten&lt;br /&gt;
&lt;br /&gt;
* Ausgänge: Ermöglicht das Einrichten zusätzlicher Ausgänge für nachfolgende Arbeitsschritte&lt;br /&gt;
&lt;br /&gt;
* Ausgang für hier erstellte Sonderobjekte: Sonderobjekte im Fenster Typ0 (nicht Typ0abc), die an diesem Schritt erstellt werden, nehmen nicht einen der im Workflow konfigurierten Ausgänge. Sie werden zu dem Schritt geleitet, den Sie im Fenster Produktionsauftrage im Register Produktionsschritte (unten rechts) eingeben können: &#039;&#039;&#039;Arbeitschritt für Sonderobjekte&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
* Serien Nr. Scanner: Schreibt die Seriennummer eines Scanners in die Bilddatei. Ermöglicht die zwingende Angabe der Seriennummer eines verwendeten Eingabegerätes / Scanners beim starten des Arbeitsfensters.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Einstellungsfenster==&lt;br /&gt;
&lt;br /&gt;
[[File:FHZ_STyp000_1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Serien Nr. Scanner===&lt;br /&gt;
&lt;br /&gt;
Verlangt die Eingabe des Namens eines EXIF Feldes. &#039;&#039;&#039;Wenn dieses Feld hier gefüllt wurde, dann muss bei dem Arbeitsschritt beim starten zwingend eine Seriennummer angegeben werden.&#039;&#039;&#039;&lt;br /&gt;
Ohne die Eingabe einer gültigen Seriennummer wird das Arbeitsfenster nicht laufen.&lt;br /&gt;
&lt;br /&gt;
Das EXIF Standard Feld für die Seriennummer lautet: &#039;&#039;&#039;SerialNumber&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die Seriennummern der Scanner werden beim beenden der Arbeit automatisch in alle Bilddateien geschrieben, bei welchen nicht bereits eine Seriennummer in dem angegebenen EXIF Feld enthalten ist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Validierung der Geräteseriennummern&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Es werden nur Seriennummer akzeptiert, welche entweder:&lt;br /&gt;
&lt;br /&gt;
*in der Liste unterhalb erfasst wurden (Die Seriennummern sind Zeilenweise (Zeilenumbruch) zu trennen!)&lt;br /&gt;
*in den Anlagen erfasst, mit einer Maschine verknüpft, einem Maschinentyp zugeordnet und dieser Maschinentyp beim Arbeitsschritt unter &amp;quot;benötigter Maschinentyp&amp;quot; konfiguriert wurde.&lt;br /&gt;
&lt;br /&gt;
[[File:FHZ_STyp000_snc.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Digitalisierungssoftware==&lt;br /&gt;
&lt;br /&gt;
Ermöglicht die Angabe einer für den Job zum Einsatz kommenden Digitalisierungsoftware und ggf. von spezifischen Software Voreinstellungen.&lt;br /&gt;
&lt;br /&gt;
Die Auswahl der benötigten Software über das Dropdown Menu lädt die dazugehörenden Einstellungsmöglichkeiten.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Die Checkbox &amp;quot;Bearbeitung ohne Digitalsierungssoftware erlauben&amp;quot; erlaubt den Start des Arbeitsfensters auch für den Fall, dass auf dem Arbeitsplatz PC die konfigurierte Software nicht verfügbar ist.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Software: Tocosa===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Jobkonfiguration über job.ini=====&lt;br /&gt;
 &lt;br /&gt;
Wird der Pfad zu einer zuvor in Tocosa vorbereiteten Job.ini Konfigurationsdatei angegeben, dann öffnet sich die Tocosa Applikation beim starten eines Auftragsobjektes mit den entsprechenden Job Einstellungen.&lt;br /&gt;
&lt;br /&gt;
Die job.ini Datei kann im gewählten Ablageordner von solchen ini Dateien beliebig benannt werden, z.B. &#039;&#039;&#039;meinScanJobNr15.ini&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Der Dateipfad bei der Einstellung &amp;quot;Pfad zur Jobkonfig.&amp;quot; muss immer vollständig, inklusive Dateiname, angegeben werden. E.g. &#039;&#039;&#039;O:\ordner\unterordner\job.ini&#039;&#039;&#039; oder &#039;&#039;&#039;O:\ordner\unterordner\meinScanJobNr15.ini&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Tocosa Grundeinstellungen über Tocosa7.ini====&lt;br /&gt;
&lt;br /&gt;
Unabhängig von den Job Einstellungen, können die Grundeinstellungen von Tocosa, welche in der Datei Tocosa7.ini gespeichert sind, geändert werden. &lt;br /&gt;
&lt;br /&gt;
Diese Datei findet sich unter C:\ProgramData\Business Graphics\Tocosa\Tocosa7.ini und sie wird mit den hier gemachten Einstellungen aktualisiert. Sollte dieser Pfad sich in einer zukünftigen Tocosa Version ändern, dann muss der Helper von der Profile dafür angepasst werden. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In der Tocosa7.ini finden sich Konfigurationsblöcke, deren Namen mit eckigen Klammern umfasst sind. Darunter finden sich die Schlüssel mit ihren Werten.&lt;br /&gt;
&lt;br /&gt;
 [Settings]&lt;br /&gt;
 LanguageFile=C:\Program Files\Tocosa\Language7.lan&lt;br /&gt;
 ShowOnScreenKeyboard=1&lt;br /&gt;
 WriteProtocol=0&lt;br /&gt;
 ThumbWidthOffset=196&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen Wert zu überschreiben, muss eine entsprechende Zeile dafür in das Textfeld eingegeben werden.&lt;br /&gt;
&lt;br /&gt;
Die Formatierung für eine Zeile ist: &amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Konfigurationsblock&#039;&#039;&#039;:&#039;&#039;Schlüssel&#039;&#039;=Wert&lt;br /&gt;
&lt;br /&gt;
 Settings:WriteProtocol=1&lt;br /&gt;
 Settings:ThumbWidthOffset=250&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Konfigurationsbeispiel in der Einstellungsmaske&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Datei: Digitalisierungssoftware.png]]&lt;br /&gt;
&lt;br /&gt;
==Essentielle Felder==&lt;br /&gt;
  HZ_TESTERGEBNISS  Metadaten- Tagname um Entscheidung zu speichern. &lt;br /&gt;
&lt;br /&gt;
  HZ_DY_SEQ         Sonder- und Kinderobjekte: Typen, welche bei der Einstellung zugelassen sind. Zu den hier angegebenen Attributstypen können Sonder- oder Kinderobjekte erstellt werden. Wenn leer, keine Sonderobjekterstellung möglich.&lt;br /&gt;
&lt;br /&gt;
  HZ_METAWERTFELD   Sonder- und Kinderobjekte: Formel zur Berechnung der Signatur für Kindesobjekte. Leer lassen, wenn der Name / die Signatur manuell eingegeben werden muss.&lt;br /&gt;
&lt;br /&gt;
  HZ_XMPSCHEMANAME  Name des EXIF Feldes der Bilddatei, in welche die Seriennummer des Eingabegerätes / Scanners geschrieben werden soll&lt;br /&gt;
&lt;br /&gt;
  HZ_BARCODEWERT    Valide Seriennummern von Eingabegeräten, welche beim start des Arbeitsfenster eingegeben werden müssen und über diese Einträge hier validiert werden.&lt;br /&gt;
&lt;br /&gt;
  HZ_FORMEL         Hält den Checkboxstatus der anzuzeigenden Metadaten durch speichern der zugehörigen AT_SEQ (YES:2454, NO:2455, ...)&lt;br /&gt;
&lt;br /&gt;
  HZ_FILEVERHALTEN        Sollen Filetests bei Feierabend ausgeführt werden?&lt;br /&gt;
&lt;br /&gt;
=Zugehörige Eingabemasken / Fenstertypen=&lt;br /&gt;
&lt;br /&gt;
Aktuell sind vier Fenstermasken / Untersystemtyp für einen Digitalisierungsarbeitschritt konfigurierbar.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;FDO_SHZTyp0 - Standardfenster mit Eingabe von Metadaten und Sonderobjekterzeugung zum Bearbeiteten Hauptobjekt&lt;br /&gt;
&lt;br /&gt;
[[File:FDO_SHZTyp0.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;FDO_SHZTyp0a - Wie Typ0, jedoch zusätzlich mit Dateierzeugung zu den Sonderobjekten&lt;br /&gt;
&lt;br /&gt;
[[File:FDO_SHZTyp0a.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;FDO_SHZTyp0b - Wie Typ0a, jedoch zusätzlich mit Datei- und Unterordnererzeugung zu den Sonderobjekten&lt;br /&gt;
&lt;br /&gt;
[[File:FDO_SHZTyp0b.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;FDO_SHZTyp0c - Zur Erstellung von Kindsobjekten mit Metadaten und Dateien. Das Hauptobjekt (Vater) kann nicht bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;HZ Konfiguration: Die Daten dürfen nicht auf dem Server gespeichert werden! &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zeigt die Metadaten des Hauptobjektes im oberen Teil an. Diese können nicht verändert werden.&lt;br /&gt;
&lt;br /&gt;
Wenn für Kindesobjekte der Typ angegeben wurde, wird &amp;quot;Unterobjekte erzeugen&amp;quot; angezeigt. Die verfügbaren Typen finden sich im Dropdown Menu &amp;quot;Typ&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Befinden sich zum Zeitpunkt der Erstellung eines Kindobjektes Dateien im Ordner c:\work\output, dann werden diese dem Kindobjekt zugeordnet und auf den Server kopiert. &lt;br /&gt;
&lt;br /&gt;
Alle Kinder des Hauptobjektes werden in der untersten Liste angezeigt.&lt;br /&gt;
&lt;br /&gt;
Die Signatur des Kindobjektes kann im Einstellungsfenster vorgegeben werden. Das Eingabefeld wird dann zu einem Anzeigefeld und kann nicht mehr überschrieben werden. &lt;br /&gt;
&lt;br /&gt;
Sie können die üblichen [[Omnisgrundlagen|Omnis-Funktionen]] benutzen. Das Feld kennt die Variable &#039;Zähler&#039;, welche ein automatisches hochzählen ermöglich.&lt;br /&gt;
&lt;br /&gt;
Auf die Signatur des Vaterobjektes kann nicht zugegriffen werden. Der Name für die Signatur muss hier festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
  con(&#039;MeineSignatur&#039;,[Zähler])&lt;br /&gt;
&lt;br /&gt;
[[File:FDO_SHZTyp0c.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Normaler_Arbeitsschritt&amp;diff=9348</id>
		<title>Normaler Arbeitsschritt</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Normaler_Arbeitsschritt&amp;diff=9348"/>
		<updated>2025-09-29T07:43:44Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3537: Keine Filtests bei Feierabend ausführen&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  2237&lt;br /&gt;
;Systemtyp: &lt;br /&gt;
  0&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
Dieser Arbeitsschritt wird zB fürs Digitalisieren oder andere manuelle Tätigkeiten an Files verwendet. Er legt die Daten des vorherigen Arbeitschrittes eines Objektes in C:\Work\Input und erwartet die Daten nach der manuellen Bearbeitung in C:\Work\Output.&lt;br /&gt;
===Digitalisieren===&lt;br /&gt;
Digitalisieren Sie alles in C:\Work\Output.&lt;br /&gt;
===Manuelle Bearbeitung von Files===&lt;br /&gt;
&lt;br /&gt;
===Leistungen===&lt;br /&gt;
Beim Starten des Schrittes wird Name und Änderungsdatum der Files im Ordner C:\Work\Output in einer Liste gespeichert. Am Beenden wird die Liste mit dem dann aktuellen Inhalt verglichen. Es können folgenden Leistungen vorkommen:&lt;br /&gt;
;Datei, Create: Eine Datei mit diesem Namen existierte beim Start noch nicht.&lt;br /&gt;
;Datei, Update: Eine Datei mit diesem Namen existierte beim Start schon, hat am Ende aber ein anderes Änderungsdatum.&lt;br /&gt;
;Datei, Delete: Eine Datei mit diesem Namen existierte beim Start, fehlt aber am Ende.&lt;br /&gt;
;Sonderobjekte: Ein Sonderobjekt wurde erstellt.&lt;br /&gt;
&lt;br /&gt;
=Konfiguration=&lt;br /&gt;
&lt;br /&gt;
* Generell&lt;br /&gt;
&lt;br /&gt;
* File Test, Die Filetests sind hier nicht rekursiv. Es werden nur die Files auf der obersten Ebene im Arbeitsordner kontrolliert. Die Filetests können bei &amp;quot;Feierabend&amp;quot; ausgestellt werden.&lt;br /&gt;
&lt;br /&gt;
* Metadaten&lt;br /&gt;
&lt;br /&gt;
* Ausgänge: Ermöglicht das Einrichten zusätzlicher Ausgänge für nachfolgende Arbeitsschritte&lt;br /&gt;
&lt;br /&gt;
* Ausgang für hier erstellte Sonderobjekte: Sonderobjekte im Fenster Typ0 (nicht Typ0abc), die an diesem Schritt erstellt werden, nehmen nicht einen der im Workflow konfigurierten Ausgänge. Sie werden zu dem Schritt geleitet, den Sie im Fenster Produktionsauftrage im Register Produktionsschritte (unten rechts) eingeben können: &#039;&#039;&#039;Arbeitschritt für Sonderobjekte&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
* Serien Nr. Scanner: Schreibt die Seriennummer eines Scanners in die Bilddatei. Ermöglicht die zwingende Angabe der Seriennummer eines verwendeten Eingabegerätes / Scanners beim starten des Arbeitsfensters.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Einstellungsfenster==&lt;br /&gt;
&lt;br /&gt;
[[File:FHZ_STyp000_1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Serien Nr. Scanner===&lt;br /&gt;
&lt;br /&gt;
Verlangt die Eingabe des Namens eines EXIF Feldes. &#039;&#039;&#039;Wenn dieses Feld hier gefüllt wurde, dann muss bei dem Arbeitsschritt beim starten zwingend eine Seriennummer angegeben werden.&#039;&#039;&#039;&lt;br /&gt;
Ohne die Eingabe einer gültigen Seriennummer wird das Arbeitsfenster nicht laufen.&lt;br /&gt;
&lt;br /&gt;
Das EXIF Standard Feld für die Seriennummer lautet: &#039;&#039;&#039;SerialNumber&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die Seriennummern der Scanner werden beim beenden der Arbeit automatisch in alle Bilddateien geschrieben, bei welchen nicht bereits eine Seriennummer in dem angegebenen EXIF Feld enthalten ist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Validierung der Geräteseriennummern&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Es werden nur Seriennummer akzeptiert, welche entweder:&lt;br /&gt;
&lt;br /&gt;
*in der Liste unterhalb erfasst wurden (Die Seriennummern sind Zeilenweise (Zeilenumbruch) zu trennen!)&lt;br /&gt;
*in den Anlagen erfasst, mit einer Maschine verknüpft, einem Maschinentyp zugeordnet und dieser Maschinentyp beim Arbeitsschritt unter &amp;quot;benötigter Maschinentyp&amp;quot; konfiguriert wurde.&lt;br /&gt;
&lt;br /&gt;
[[File:FHZ_STyp000_snc.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Digitalisierungssoftware==&lt;br /&gt;
&lt;br /&gt;
Ermöglicht die Angabe einer für den Job zum Einsatz kommenden Digitalisierungsoftware und ggf. von spezifischen Software Voreinstellungen.&lt;br /&gt;
&lt;br /&gt;
Die Auswahl der benötigten Software über das Dropdown Menu lädt die dazugehörenden Einstellungsmöglichkeiten.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Die Checkbox &amp;quot;Bearbeitung ohne Digitalsierungssoftware erlauben&amp;quot; erlaubt den Start des Arbeitsfensters auch für den Fall, dass auf dem Arbeitsplatz PC die konfigurierte Software nicht verfügbar ist.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Software: Tocosa===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Jobkonfiguration über job.ini=====&lt;br /&gt;
 &lt;br /&gt;
Wird der Pfad zu einer zuvor in Tocosa vorbereiteten Job.ini Konfigurationsdatei angegeben, dann öffnet sich die Tocosa Applikation beim starten eines Auftragsobjektes mit den entsprechenden Job Einstellungen.&lt;br /&gt;
&lt;br /&gt;
Die job.ini Datei kann im gewählten Ablageordner von solchen ini Dateien beliebig benannt werden, z.B. &#039;&#039;&#039;meinScanJobNr15.ini&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Der Dateipfad bei der Einstellung &amp;quot;Pfad zur Jobkonfig.&amp;quot; muss immer vollständig, inklusive Dateiname, angegeben werden. E.g. &#039;&#039;&#039;O:\ordner\unterordner\job.ini&#039;&#039;&#039; oder &#039;&#039;&#039;O:\ordner\unterordner\meinScanJobNr15.ini&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Tocosa Grundeinstellungen über Tocosa7.ini====&lt;br /&gt;
&lt;br /&gt;
Unabhängig von den Job Einstellungen, können die Grundeinstellungen von Tocosa, welche in der Datei Tocosa7.ini gespeichert sind, geändert werden. &lt;br /&gt;
&lt;br /&gt;
Diese Datei findet sich unter C:\ProgramData\Business Graphics\Tocosa\Tocosa7.ini und sie wird mit den hier gemachten Einstellungen aktualisiert. Sollte dieser Pfad sich in einer zukünftigen Tocosa Version ändern, dann muss der Helper von der Profile dafür angepasst werden. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In der Tocosa7.ini finden sich Konfigurationsblöcke, deren Namen mit eckigen Klammern umfasst sind. Darunter finden sich die Schlüssel mit ihren Werten.&lt;br /&gt;
&lt;br /&gt;
 [Settings]&lt;br /&gt;
 LanguageFile=C:\Program Files\Tocosa\Language7.lan&lt;br /&gt;
 ShowOnScreenKeyboard=1&lt;br /&gt;
 WriteProtocol=0&lt;br /&gt;
 ThumbWidthOffset=196&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen Wert zu überschreiben, muss eine entsprechende Zeile dafür in das Textfeld eingegeben werden.&lt;br /&gt;
&lt;br /&gt;
Die Formatierung für eine Zeile ist: &amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Konfigurationsblock&#039;&#039;&#039;:&#039;&#039;Schlüssel&#039;&#039;=Wert&lt;br /&gt;
&lt;br /&gt;
 Settings:WriteProtocol=1&lt;br /&gt;
 Settings:ThumbWidthOffset=250&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Konfigurationsbeispiel in der Einstellungsmaske&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Datei: Digitalisierungssoftware.png]]&lt;br /&gt;
&lt;br /&gt;
==Essentielle Felder==&lt;br /&gt;
  HZ_TESTERGEBNISS  Metadaten- Tagname um Entscheidung zu speichern. &lt;br /&gt;
&lt;br /&gt;
  HZ_DY_SEQ         Sonder- und Kinderobjekte: Typen, welche bei der Einstellung zugelassen sind. Zu den hier angegebenen Attributstypen können Sonder- oder Kinderobjekte erstellt werden. Wenn leer, keine Sonderobjekterstellung möglich.&lt;br /&gt;
&lt;br /&gt;
  HZ_METAWERTFELD   Sonder- und Kinderobjekte: Formel zur Berechnung der Signatur für Kindesobjekte. Leer lassen, wenn der Name / die Signatur manuell eingegeben werden muss.&lt;br /&gt;
&lt;br /&gt;
  HZ_XMPSCHEMANAME  Name des EXIF Feldes der Bilddatei, in welche die Seriennummer des Eingabegerätes / Scanners geschrieben werden soll&lt;br /&gt;
&lt;br /&gt;
  HZ_BARCODEWERT    Valide Seriennummern von Eingabegeräten, welche beim start des Arbeitsfenster eingegeben werden müssen und über diese Einträge hier validiert werden.&lt;br /&gt;
&lt;br /&gt;
  HZ_FORMEL         Hält den Checkboxstatus der anzuzeigenden Metadaten durch speichern der zugehörigen AT_SEQ (YES:2454, NO:2455, ...)&lt;br /&gt;
&lt;br /&gt;
  HZ_HASHTYP        Sollen Filetests bei Feierabend ausgeführt werden?&lt;br /&gt;
&lt;br /&gt;
=Zugehörige Eingabemasken / Fenstertypen=&lt;br /&gt;
&lt;br /&gt;
Aktuell sind vier Fenstermasken / Untersystemtyp für einen Digitalisierungsarbeitschritt konfigurierbar.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;FDO_SHZTyp0 - Standardfenster mit Eingabe von Metadaten und Sonderobjekterzeugung zum Bearbeiteten Hauptobjekt&lt;br /&gt;
&lt;br /&gt;
[[File:FDO_SHZTyp0.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;FDO_SHZTyp0a - Wie Typ0, jedoch zusätzlich mit Dateierzeugung zu den Sonderobjekten&lt;br /&gt;
&lt;br /&gt;
[[File:FDO_SHZTyp0a.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;FDO_SHZTyp0b - Wie Typ0a, jedoch zusätzlich mit Datei- und Unterordnererzeugung zu den Sonderobjekten&lt;br /&gt;
&lt;br /&gt;
[[File:FDO_SHZTyp0b.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;FDO_SHZTyp0c - Zur Erstellung von Kindsobjekten mit Metadaten und Dateien. Das Hauptobjekt (Vater) kann nicht bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;HZ Konfiguration: Die Daten dürfen nicht auf dem Server gespeichert werden! &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zeigt die Metadaten des Hauptobjektes im oberen Teil an. Diese können nicht verändert werden.&lt;br /&gt;
&lt;br /&gt;
Wenn für Kindesobjekte der Typ angegeben wurde, wird &amp;quot;Unterobjekte erzeugen&amp;quot; angezeigt. Die verfügbaren Typen finden sich im Dropdown Menu &amp;quot;Typ&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Befinden sich zum Zeitpunkt der Erstellung eines Kindobjektes Dateien im Ordner c:\work\output, dann werden diese dem Kindobjekt zugeordnet und auf den Server kopiert. &lt;br /&gt;
&lt;br /&gt;
Alle Kinder des Hauptobjektes werden in der untersten Liste angezeigt.&lt;br /&gt;
&lt;br /&gt;
Die Signatur des Kindobjektes kann im Einstellungsfenster vorgegeben werden. Das Eingabefeld wird dann zu einem Anzeigefeld und kann nicht mehr überschrieben werden. &lt;br /&gt;
&lt;br /&gt;
Sie können die üblichen [[Omnisgrundlagen|Omnis-Funktionen]] benutzen. Das Feld kennt die Variable &#039;Zähler&#039;, welche ein automatisches hochzählen ermöglich.&lt;br /&gt;
&lt;br /&gt;
Auf die Signatur des Vaterobjektes kann nicht zugegriffen werden. Der Name für die Signatur muss hier festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
  con(&#039;MeineSignatur&#039;,[Zähler])&lt;br /&gt;
&lt;br /&gt;
[[File:FDO_SHZTyp0c.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Filehandling&amp;diff=9334</id>
		<title>Filehandling</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Filehandling&amp;diff=9334"/>
		<updated>2025-08-20T08:43:05Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3522: Wiki aktualisisert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  2377&lt;br /&gt;
;Systemtyp: &lt;br /&gt;
  59&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
Dieser Arbeitsschritt kann verschiedene Aktionen wie zB. Files bewegen, Ordner erstellen etc. im DO Ordner vornehmen.&lt;br /&gt;
&lt;br /&gt;
Mögliche Befehle:&lt;br /&gt;
* Erstelle Ordner&lt;br /&gt;
* Lösche Ordner&lt;br /&gt;
* Kopiere Dateien von XX nach XX&lt;br /&gt;
* Bewege Dateien von XX nach XX&lt;br /&gt;
* Lösche Datei(en) nach Name&lt;br /&gt;
* Lösche Datei(en) nach Position&lt;br /&gt;
* Kopiere Dateien des Vaters von XX nach XX&lt;br /&gt;
* Kopiere Dateien des Grossvaters von XX nach XX&lt;br /&gt;
* Lösche alle Dateien mit einem Barcode des Typs XX mit einem Wert YY&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Befehle können 2 Varianten von Errorhandling vorweisen:&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;zwingend erfolgreich [!]:&#039;&#039;&#039; Jeder Fehler wirft ein DO Fehler. Auch wenn zB. konfiguriert ist, dass ein File test.txt von A nach B kopiert werden soll und das File jedoch nicht gefunden wurde.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;nicht zwingend erfolgreich:&#039;&#039;&#039; Ziemlich schwaches Errorhandling. Nur schwere Fehler verursachen einene DO Fehler. Sollte zB. benutzt werden &amp;quot;falls&amp;quot; ein File von A nach B kopiert werden soll, sofern es existiert.&lt;br /&gt;
&lt;br /&gt;
==Essentielle Felder==&lt;br /&gt;
  HZ_FORMEL   &#039;&#039;Konfiguration welche Befehle ausgeführt werden sollen&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  HZ_DATENHOLEN   &#039;&#039;0 = Daten bleiben beim letzten Datenschritt. Somit wird die letzte vorhandene Version Ihrer Daten bearbeitet (!), 1 = Daten werden vor dem Ausführen der Befehle an den aktuellen Schritt kopiert. Somit werden die Befehle auf einer Kopie der Daten durchgeführt (Normalfall), 2 = Es wird ein neuer, leerer DO Ordner erstellt&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Erlaubte Werte für die Konfiguration:==&lt;br /&gt;
Beim Auswählen von Files kann entweder genau 1 File via Name angegeben werden, oder es können &amp;quot;*&amp;quot; im Dateinamen eingebunden werden um mehrere Files anzusprechen.&lt;br /&gt;
&lt;br /&gt;
;Beispiel:&lt;br /&gt;
&lt;br /&gt;
  Alle TIF&#039;s in einem Ordner: &amp;quot;*.tif&amp;quot;&lt;br /&gt;
  Alle Dateien welche mit &amp;quot;a&amp;quot; starten: &amp;quot;a*.*&amp;quot;&lt;br /&gt;
  Alle Dateien welche mit &amp;quot;a&amp;quot; starten, mit &amp;quot;e&amp;quot; enden und vom Typ txt sind: &amp;quot;a*e.txt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Verhalten Daten holen:==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Aktion am letzten Datenschritt ausführen:&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Die Aktionen werden im Ordner des letzten Datenschrittes des DO Objektes ausgeführt. Die Daten an diesem Schritt werden damit z.B. unwiederruflich gelöscht.&lt;br /&gt;
Vermeidet das unnötige duplizieren der Daten an einen neuen Schritt, wenn zum bsp. die Ordnerstruktur geändert werden soll.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Daten an diesen Schritt kopieren und Aktionen ausführen:&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Kopiert und dupliziert damit alle Daten des letzten Datenschrittes des DO an den aktuellen Datenschritt dieses Arbeitsschrittes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Neuen DO Ordner erstellen:&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Erstellt einen Ordner für das Do Objekt am Datenschritt dieses Arbeitsschrittes. Wird zwingend benötigt, für die kopieren Schritte der Daten des Vaters oder des Grossvaters, wenn für das DO Objekt selbst keine Daten aus einem früheren Arbeitsschritt exisitieren oder diese nicht mit den Daten der Ahnen zusammengeführt werden sollen!&lt;br /&gt;
&lt;br /&gt;
===Version 0===&lt;br /&gt;
Hier werden die Parameter, wie der Dateiname/Ordnername nicht evaluiert. Sie können keine Metadaten verwenden. &lt;br /&gt;
===Version 1===&lt;br /&gt;
Hier können Sie Metadaten verwenden in den Parametern. Die Parameter müssen korrekte Formeln sein und einfache Zeichenfolgen sind in Anführungszeichen einzugeben.  &lt;br /&gt;
&lt;br /&gt;
z.B.: &lt;br /&gt;
  con([^DOSignatur],&#039;_komprimiert&#039;)&lt;br /&gt;
  &#039;*.tif&#039;&lt;br /&gt;
Sie können die üblichen Platzhalter verwenden. Somit ist es möglich in jedem DO einen anderen Unterordner zu erstellen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Befehle:==&lt;br /&gt;
&lt;br /&gt;
===Erstelle Ordner===&lt;br /&gt;
&lt;br /&gt;
===Lösche Ordner===&lt;br /&gt;
&lt;br /&gt;
===Kopiere Dateien von XX nach XX===&lt;br /&gt;
&lt;br /&gt;
===Bewege Dateien von XX nach XX===&lt;br /&gt;
&lt;br /&gt;
===Lösche Datei(en) nach Name===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Lösche Datei(en) nach Position===&lt;br /&gt;
&lt;br /&gt;
Dateien können anhand ihrer Sortierposition inerhalb des Dateisystems gelöscht werden. Die zu löschenden Positionen werden hier als Kommagetrennte Zahlenfolge eingegeben.&lt;br /&gt;
&lt;br /&gt;
Die verwendung der Literale &amp;quot;U&amp;quot; und &amp;quot;G&amp;quot; ermöglichen das löschen aller &#039;&#039;&#039;G&#039;&#039;&#039;eraden oder aller &#039;&#039;&#039;U&#039;&#039;&#039;ngeraden Positionen. Die Literale dürfen jedoch nicht beide gleichzeitig verwendet werden, um damit z.B. alle Dateien zu löschen.&lt;br /&gt;
&lt;br /&gt;
Es sind positive und negative Zahlen als Positionswerte möglich. &lt;br /&gt;
&lt;br /&gt;
Negative Werte zählen von der letzten Datei ausgehend rückwarts. &#039;&#039;&#039;Wobei -1 = letzte Datei, -2 = vorletzte Datei.&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
Positive Werte zählen von der ersten Datei ausgehend vorwärts. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Die Reihenfolge der Positionseingabe&#039;&#039; &#039;&#039;&#039;ist nicht relevant.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Bsp.: &lt;br /&gt;
&lt;br /&gt;
Lösche die Dateien nummer drei, fünfzehn sowie die drittletzte -&amp;gt; &#039;3,15,-3&#039; (ist gleich wie &#039;15,-3,3&#039;) &lt;br /&gt;
&lt;br /&gt;
Lösche alle geraden, die nummern 7, 17 und die letzte -&amp;gt; &#039;G,7,17,-1&#039; (ist gleich wie &#039;-1,7,17,G&#039;)&lt;br /&gt;
&lt;br /&gt;
Lösche alle ungeraden -&amp;gt; &#039;U&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Verhalten bei angewählter Option &#039;zwingend erforderlich&#039; verlangt, dass alle genannten Dateipositionen vorhanden sein müssen!: &lt;br /&gt;
&lt;br /&gt;
* Sollen gerade Dateien (G) gelöscht werden, und es gibt bloss eine einzige Datei, erzeugt dies einen DO Fehler.&lt;br /&gt;
* Soll die Datei -15 gelöscht werden, und es gibt bloss 14 Dateien, erzeugt dies einen DO Fehler.&lt;br /&gt;
&lt;br /&gt;
===Kopiere Dateien des Vaters von XX nach XX===&lt;br /&gt;
&lt;br /&gt;
===Kopiere Dateien des Grossvaters von XX nach XX===&lt;br /&gt;
&lt;br /&gt;
===Erstelle Kindsordner===&lt;br /&gt;
&lt;br /&gt;
Erstellt im aktuellen Ordner des Objektes Unterordner mit den Namen der Signaturen seiner Kindesobjekte.&lt;br /&gt;
&lt;br /&gt;
Bsp.: Das Objekt hat fünf Kindobjekte mit den Signaturen A1, A2, A3, A4, A5.&lt;br /&gt;
Wenn das Objekt den Befehl durchlaufen hat, befinden sich im aktuellen Ordner des Objektes, nebst bereits vorhandenen Ordnern oder Dateien, fünf neue Ordner mit den Namen A1, A2, A3, A4, A5.&lt;br /&gt;
&lt;br /&gt;
===Lösche alle Dateien mit einem Barcode des Typs XX mit einem Wert YY===&lt;br /&gt;
Dieser Befehlt löscht alle Bilder welche einen Barcode besitzen. Sie können den Typ des Barcodes wählen sowie der Barcodewert. Beachten Sie, dass bei der Serverjob Version 1 die Formel evaluiert wird. Somit können Sie die üblichen Platzhalter und Funktionen verwenden.&lt;br /&gt;
&lt;br /&gt;
===Lösche alle Dateien und folgende mit einem Barcode des Typs XX mit einem Wert YY===&lt;br /&gt;
Dieser Befehl such den 1. Barcode mit dem Typd un Wert und löscht diesen und alle darauf folgenden Files. Sie können den Typ des Barcodes wählen sowie der Barcodewert. Beachten Sie, dass bei der Serverjob Version 1 die Formel evaluiert wird. Somit können Sie die üblichen Platzhalter und Funktionen verwenden.&lt;br /&gt;
&lt;br /&gt;
==Pane im Produktionsauftrag (FHK_Maske)==&lt;br /&gt;
&lt;br /&gt;
[[File:Filehandling.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Filehandling&amp;diff=9322</id>
		<title>Filehandling</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Filehandling&amp;diff=9322"/>
		<updated>2025-07-24T08:33:38Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3522: Wiki aktualisiert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  2377&lt;br /&gt;
;Systemtyp: &lt;br /&gt;
  59&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
Dieser Arbeitsschritt kann verschiedene Aktionen wie zB. Files bewegen, Ordner erstellen etc. im DO Ordner vornehmen.&lt;br /&gt;
&lt;br /&gt;
Mögliche Befehle:&lt;br /&gt;
* Erstelle Ordner&lt;br /&gt;
* Lösche Ordner&lt;br /&gt;
* Kopiere Dateien von XX nach XX&lt;br /&gt;
* Bewege Dateien von XX nach XX&lt;br /&gt;
* Lösche Datei(en) nach Name&lt;br /&gt;
* Lösche Datei(en) nach Position&lt;br /&gt;
* Kopiere Dateien des Vaters von XX nach XX&lt;br /&gt;
* Kopiere Dateien des Grossvaters von XX nach XX&lt;br /&gt;
* Lösche alle Dateien mit einem Barcode des Typs XX mit einem Wert YY&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Befehle können 2 Varianten von Errorhandling vorweisen:&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;zwingend erfolgreich [!]:&#039;&#039;&#039; Jeder Fehler wirft ein DO Fehler. Auch wenn zB. konfiguriert ist, dass ein File test.txt von A nach B kopiert werden soll und das File jedoch nicht gefunden wurde.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;nicht zwingend erfolgreich:&#039;&#039;&#039; Ziemlich schwaches Errorhandling. Nur schwere Fehler verursachen einene DO Fehler. Sollte zB. benutzt werden &amp;quot;falls&amp;quot; ein File von A nach B kopiert werden soll, sofern es existiert.&lt;br /&gt;
&lt;br /&gt;
==Essentielle Felder==&lt;br /&gt;
  HZ_FORMEL   &#039;&#039;Konfiguration welche Befehle ausgeführt werden sollen&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  HZ_DATENHOLEN   &#039;&#039;0 = Daten bleiben beim letzten Datenschritt. Somit wird die letzte vorhandene Version Ihrer Daten bearbeitet (!), 1 = Daten werden vor dem Ausführen der Befehle an den aktuellen Schritt kopiert. Somit werden die Befehle auf einer Kopie der Daten durchgeführt (Normalfall), 2 = Es wird ein neuer, leerer DO Ordner erstellt&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Erlaubte Werte für die Konfiguration:==&lt;br /&gt;
Beim Auswählen von Files kann entweder genau 1 File via Name angegeben werden, oder es können &amp;quot;*&amp;quot; im Dateinamen eingebunden werden um mehrere Files anzusprechen.&lt;br /&gt;
&lt;br /&gt;
;Beispiel:&lt;br /&gt;
&lt;br /&gt;
  Alle TIF&#039;s in einem Ordner: &amp;quot;*.tif&amp;quot;&lt;br /&gt;
  Alle Dateien welche mit &amp;quot;a&amp;quot; starten: &amp;quot;a*.*&amp;quot;&lt;br /&gt;
  Alle Dateien welche mit &amp;quot;a&amp;quot; starten, mit &amp;quot;e&amp;quot; enden und vom Typ txt sind: &amp;quot;a*e.txt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Verhalten Daten holen:==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Aktion am letzten Datenschritt ausführen:&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Die Aktionen werden im Ordner des letzten Datenschrittes des DO Objektes ausgeführt. Die Daten an diesem Schritt werden damit z.B. unwiederruflich gelöscht.&lt;br /&gt;
Vermeidet das unnötige duplizieren der Daten an einen neuen Schritt, wenn zum bsp. die Ordnerstruktur geändert werden soll.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Daten an diesen Schritt kopieren und Aktionen ausführen:&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Kopiert und dupliziert damit alle Daten des letzten Datenschrittes des DO an den aktuellen Datenschritt dieses Arbeitsschrittes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Neuen DO Ordner erstellen:&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Erstellt einen Ordner für das Do Objekt am Datenschritt dieses Arbeitsschrittes. Wird zwingend benötigt, für die kopieren Schritte der Daten des Vaters oder des Grossvaters, wenn für das DO Objekt selbst keine Daten aus einem früheren Arbeitsschritt exisitieren oder diese nicht mit den Daten der Ahnen zusammengeführt werden sollen!&lt;br /&gt;
&lt;br /&gt;
===Version 0===&lt;br /&gt;
Hier werden die Parameter, wie der Dateiname/Ordnername nicht evaluiert. Sie können keine Metadaten verwenden. &lt;br /&gt;
===Version 1===&lt;br /&gt;
Hier können Sie Metadaten verwenden in den Parametern. Die Parameter müssen korrekte Formeln sein und einfache Zeichenfolgen sind in Anführungszeichen einzugeben.  &lt;br /&gt;
&lt;br /&gt;
z.B.: &lt;br /&gt;
  con([^DOSignatur],&#039;_komprimiert&#039;)&lt;br /&gt;
  &#039;*.tif&#039;&lt;br /&gt;
Sie können die üblichen Platzhalter verwenden. Somit ist es möglich in jedem DO einen anderen Unterordner zu erstellen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Befehle:==&lt;br /&gt;
&lt;br /&gt;
===Erstelle Ordner===&lt;br /&gt;
&lt;br /&gt;
===Lösche Ordner===&lt;br /&gt;
&lt;br /&gt;
===Kopiere Dateien von XX nach XX===&lt;br /&gt;
&lt;br /&gt;
===Bewege Dateien von XX nach XX===&lt;br /&gt;
&lt;br /&gt;
===Lösche Datei(en) nach Name===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Lösche Datei(en) nach Position===&lt;br /&gt;
&lt;br /&gt;
Dateien können anhand ihrer Sortierposition inerhalb des Dateisystems gelöscht werden. Die zu löschenden Positionen werden hier als Kommagetrennte Zahlenfolge eingegeben.&lt;br /&gt;
&lt;br /&gt;
Die verwendung der Literale &amp;quot;U&amp;quot; und &amp;quot;G&amp;quot; ermöglichen das löschen aller &#039;&#039;&#039;G&#039;&#039;&#039;eraden oder aller &#039;&#039;&#039;U&#039;&#039;&#039;ngeraden Positionen. Die Literale dürfen jedoch nicht beide gleichzeitig verwendet werden, um damit z.B. alle Dateien zu löschen.&lt;br /&gt;
&lt;br /&gt;
Es sind positive und negative Zahlen als Positionswerte möglich. &lt;br /&gt;
&lt;br /&gt;
Negative Werte zählen von der letzten Datei ausgehend rückwarts. &#039;&#039;&#039;Wobei -1 = letzte Datei, -2 = vorletzte Datei.&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
Positive Werte zählen von der ersten Datei ausgehend vorwärts. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Die Reihenfolge der Positionseingabe&#039;&#039; &#039;&#039;&#039;ist nicht relevant.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Bsp.: &lt;br /&gt;
&lt;br /&gt;
Lösche die Dateien nummer drei, fünfzehn sowie die drittletzte -&amp;gt; &#039;3,15,-3&#039; (ist gleich wie &#039;15,-3,3&#039;) &lt;br /&gt;
&lt;br /&gt;
Lösche alle geraden, die nummern 7, 17 und die letzte -&amp;gt; &#039;G,7,17,-1&#039; (ist gleich wie &#039;-1,7,17,G&#039;)&lt;br /&gt;
&lt;br /&gt;
Lösche alle ungeraden -&amp;gt; &#039;U&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Verhalten bei angewählter Option &#039;zwingend erforderlich&#039; verlangt, dass alle genannten Dateipositionen vorhanden sein müssen!: &lt;br /&gt;
&lt;br /&gt;
* Sollen gerade Dateien (G) gelöscht werden, und es gibt bloss eine einzige Datei, erzeugt dies einen DO Fehler.&lt;br /&gt;
* Soll die Datei -15 gelöscht werden, und es gibt bloss 14 Dateien, erzeugt dies einen DO Fehler.&lt;br /&gt;
&lt;br /&gt;
===Kopiere Dateien des Vaters von XX nach XX===&lt;br /&gt;
&lt;br /&gt;
===Kopiere Dateien des Grossvaters von XX nach XX===&lt;br /&gt;
&lt;br /&gt;
===Erstelle Kindsordner===&lt;br /&gt;
&lt;br /&gt;
Erstellt im aktuellen Ordner des Objektes Unterordner mit den Namen der Signaturen seiner Kindesobjekte.&lt;br /&gt;
&lt;br /&gt;
Bsp.: Das Objekt hat fünf Kindobjekte mit den Signaturen A1, A2, A3, A4, A5.&lt;br /&gt;
Wenn das Objekt den Befehl durchlaufen hat, befinden sich im aktuellen Ordner des Objektes, nebst bereits vorhandenen Ordnern oder Dateien, fünf neue Ordner mit den Namen A1, A2, A3, A4, A5.&lt;br /&gt;
&lt;br /&gt;
===Lösche alle Dateien mit einem Barcode des Typs XX mit einem Wert YY===&lt;br /&gt;
Dieser Befehlt löscht alle Bilder welche einen Barcode besitzen. Sie können den Typ des Barcodes wählen sowie der Barcodewert. Beachten Sie, dass bei der Serverjob Version 1 die Formel evaluiert wird. Somit können Sie die üblichen Platzhalter und Funktionen verwenden.&lt;br /&gt;
&lt;br /&gt;
==Pane im Produktionsauftrag (FHK_Maske)==&lt;br /&gt;
&lt;br /&gt;
[[File:Filehandling.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Generische_Vorerfassung&amp;diff=9321</id>
		<title>Generische Vorerfassung</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Generische_Vorerfassung&amp;diff=9321"/>
		<updated>2025-07-23T09:23:56Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3519: Wiki erstellt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  3519&lt;br /&gt;
;Systemtyp: &lt;br /&gt;
  76&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
Mit diesem Arbeitsschritt kann eine generische Vorerfassung von Objekten konfiguriert werden. Dazu gibt es ein Modul namens &amp;quot;Generische Vorerfassung&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==Konfiguration==&lt;br /&gt;
&lt;br /&gt;
[[Datei:Generische Vorerfassung.png|400px]]&lt;br /&gt;
&lt;br /&gt;
===Punkt 1===&lt;br /&gt;
Wählen Sie hier alle Objekttypen aus, die Sie konfigurieren möchten. Sie können über “+” und “−” Objekttypen hinzufügen oder entfernen. Die Reihenfolge kann ebenfalls angepasst werden. Dies wirkt sich auf das Dropdown-Menü im “Generische Vorerfassungsfenster” aus.&lt;br /&gt;
&lt;br /&gt;
===Punkt 2===&lt;br /&gt;
Hier können Sie die Signatur der neu erfassten Objekte definieren. Verwenden Sie dazu alle [https://helper.ch/wiki/index.php?title=Verfügbare_Funktionen verfügbaren Funktionen]. Falls der Benutzer die Signatur selbst wählen soll, geben Sie “*” als Wert ein.&lt;br /&gt;
&lt;br /&gt;
===Punkt 3===&lt;br /&gt;
Aktivieren Sie diese Checkbox, wenn der Benutzer Objekte dieses Typs vorerfassen darf.&lt;br /&gt;
&lt;br /&gt;
===Punkt 4===&lt;br /&gt;
Wählen Sie alle Attribute aus, die dem Benutzer im “Generische Vorerfassungsfenster” angezeigt werden sollen. Auch hier können Sie die Reihenfolge der Attribute festlegen.&lt;br /&gt;
&lt;br /&gt;
===Punkt 5===&lt;br /&gt;
Wählen Sie das Objektblatt, das gedruckt werden soll. Alternativ können Sie die Option deaktivieren, sodass kein Objektblatt gedruckt wird.&lt;br /&gt;
&lt;br /&gt;
===Punkt 6===&lt;br /&gt;
Wählen Sie den Lieferschein, der gedruckt werden soll. Auch hier können Sie die Option deaktivieren, sodass kein Lieferschein gedruckt wird.&lt;br /&gt;
&lt;br /&gt;
==Fenster==&lt;br /&gt;
&lt;br /&gt;
[[Datei:Generische Vorerfassung Fenster.png|900px]]&lt;br /&gt;
===Punkt 1 - Produktionsauftrag wählen===&lt;br /&gt;
Zuerst muss der Benutzer den gewünschten Produktionsauftrag auswählen. Es stehen ihm alle Arbeitsschritte zur Verfügung, die zu Produktionsaufträgen seines Kunden gehören. Der Produktionsauftrag muss also mit dem gleichen Kunden (HK_KU_SEQ) verknüpft sein, dem auch der Benutzer zugeordnet ist (US_KU_SEQ). Ist dem Benutzer kein Kunde zugewiesen, wird er als interner Mitarbeiter betrachtet und ihm werden alle Arbeitsschritte des Systemtyps 76 angezeigt.&lt;br /&gt;
&lt;br /&gt;
Ein Wechsel zwischen Arbeitsschritten ist während der Vorerfassung möglich.&lt;br /&gt;
&lt;br /&gt;
===Punkt 2 - Treelist===&lt;br /&gt;
In der Hauptliste dieses Fensters werden alle Objekte des Produktionsauftrags angezeigt. Befinden sich die Objekte nicht mehr in diesem Arbeitsschritt, kann der Benutzer ihre Daten nicht mehr bearbeiten. Dies wird durch ein Schlosssymbol signalisiert. Für jedes Objekt werden die Signatur und die vorkonfigurierten Attribute in der festgelegten Reihenfolge angezeigt. Alle Werte sind direkt in der Liste editierbar – mit Ausnahme der Signatur, sofern keine freie Benutzereingabe (”*”) konfiguriert wurde.&lt;br /&gt;
&lt;br /&gt;
===Punkt 3 - Aktionen===&lt;br /&gt;
Der Benutzer kann mit diesen Buttons Objekte erstellen, löschen oder duplizieren. Im Objekttyp-Dropdown werden nur jene Objekttypen angezeigt, die für die Vorerfassung freigegeben sind. Auch das Duplizieren von Objekten anderer Typen ist nicht möglich. Falls konfiguriert, kann der Benutzer außerdem einen Lieferschein und ein Objektblatt drucken.&lt;br /&gt;
&lt;br /&gt;
===Punkt 4 - Statistiken===&lt;br /&gt;
Hier wird die Gesamtzahl aller Objekte der aktuellen Tranche angezeigt. Zudem gibt es eine Übersicht über die Anzahl der verschiedenen Objekttypen.&lt;br /&gt;
&lt;br /&gt;
==Essentielle Felder==&lt;br /&gt;
  HZ_FORMEL   &#039;&#039;Hier wird die gesamte Konfiguration gespeichert&#039;&#039;&lt;br /&gt;
  HZ_STRINGTRENNER   &#039;&#039;Speichert welches Objektblatt gedruckt werden soll&#039;&#039;&lt;br /&gt;
  HZ_FELDTRENNER   &#039;&#039;Speichert welcher Lieferschein gedruckt werden soll&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Datei:Generische_Vorerfassung_Fenster.png&amp;diff=9320</id>
		<title>Datei:Generische Vorerfassung Fenster.png</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Datei:Generische_Vorerfassung_Fenster.png&amp;diff=9320"/>
		<updated>2025-07-23T09:07:30Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Fenster &amp;quot;Generische Vorerfassung&amp;quot;&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Datei:Generische_Vorerfassung.png&amp;diff=9319</id>
		<title>Datei:Generische Vorerfassung.png</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Datei:Generische_Vorerfassung.png&amp;diff=9319"/>
		<updated>2025-07-23T08:55:26Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Konfigurationsfenster der Generischen Vorerfassung&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Formate_definieren&amp;diff=9316</id>
		<title>Formate definieren</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Formate_definieren&amp;diff=9316"/>
		<updated>2025-07-04T07:24:02Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3517: Wiki um nach Fläche Erweitert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Fenstername:&lt;br /&gt;
  &#039;&#039;&#039;FDY_FormateDefinieren&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Grund Idee ==&lt;br /&gt;
In diesem Fenster können Sie interessante Formate, Umfänge und Kategorien definieren, welche Sie messen möchten und somit in Auswertungen im Blick haben. Einige Beispiele: &amp;quot;Wie viele der Bücher sind dick (&amp;gt; 50 Seiten)&amp;quot;, &amp;quot;Wie viele Seiten meines Ordners sind gross (&amp;gt; A3)?&amp;quot;, &amp;quot;Wie viele Bücher kann ich als teuer verrechnen? (&amp;gt; 50 Seiten und mindestens 15 grosse Seiten)&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
In den folgenden Abschnitten werden Sie durch die Konfiguration geführt. Um das Fenster zu öffnen navigieren Sie zu Hauptmaske &amp;gt;&amp;gt; Produktionsaufträge &amp;gt;&amp;gt; Objekttypen &amp;gt;&amp;gt; Formate definieren. &amp;lt;br&amp;gt; Es ist möglich Formate, Umfänge und Kategorien für Bilder sowie für PDFs (auch gemischt) zu definieren.&lt;br /&gt;
&lt;br /&gt;
=== Allgemeine Hinweise ===&lt;br /&gt;
Alle Grenzen welche Sie angeben sind &#039;&#039;&#039;inklusive&#039;&#039;&#039;. Geben Sie also Acht, dass Sie in der nächsten Konfigurationszeile den &amp;quot;Bis&amp;quot; Wert immer um 1 erhöhen und diesen als Startwert verwenden. &amp;lt;br&amp;gt; Wichtig ist auch, dass keine Löcher oder Überschneidungen konfiguriert werden, da dies zu falschen Zahlen führen kann.&lt;br /&gt;
&lt;br /&gt;
=== Formate ===&lt;br /&gt;
[[Datei:Formate v2.png|500px]]&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
In diesem Tab können Sie Formate für einzelne Seiten definieren. Alle Höhen und Breiten Werte sind in Millimeter. Falls Sie Bilddateien in Ihrem Projekt messen nutzen Sie den [https://pixelcalculator.com/de Pixelrechner] um von px und dpi auf mm zu schliessen. In das definierte Attribut wird die Anzahl Seiten des DO gespeichert. Somit würde nach dem Messen zum Beispiel &amp;quot;20&amp;quot; im Attribut &amp;quot;AnzahlMini&amp;quot; stehen. Die Option &amp;quot;Ausrichtung egal&amp;quot; definiert, ob die Seite automatisch ins Hochformat gedreht werden soll bevor die Messungen ausgeführt werden. Falls Sie &amp;quot;nach Fläche&amp;quot; wählen, wird die Fläche der Datei für den Abgleich verwendet. Dies ist vor allem Sinnvoll, wenn spezielle Dateiformate in diesem Projekt vorkommen können. Sie müssen immer das ganze Spektrum von 0 - 999999 mm in Ihrer Konfiguration abdecken damit alle Seiten sicherlich zu einem Format gehören.&lt;br /&gt;
&lt;br /&gt;
=== Umfänge ===&lt;br /&gt;
[[Datei:Umfänge.png|500px|rahmenlos]]&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
In diesem Tab können Sie Umfänge für DO-Objekte definieren. In das Attribut wird der Name des Umfanges geschrieben. Also steht zum Beispiel im Attribut &amp;quot;Umfang&amp;quot; am Ende &amp;quot;mittel&amp;quot; sofern das Objekt zwischen 21 - 40 Seiten hat. Sie müssen immer das ganze Spektrum von 0 - 99999 Seiten in Ihrer Konfiguration abdecken damit alle Objekte sicherlich zu einem Umfang gehören.&lt;br /&gt;
&lt;br /&gt;
=== Kategorien ===&lt;br /&gt;
[[Datei:Kategorien.png|500px|rahmenlos]]&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
In diesem Tab können Sie Kategorien für DO-Objekte definieren. In das Attribut wird immer der Name der &#039;&#039;&#039;letzten&#039;&#039;&#039; passenden Konfiguration geschrieben. In der Formel können Sie &#039;&#039;&#039;alle&#039;&#039;&#039; Attribute des Objektes verwenden, auch diese welche in der Konfiguration der Formate und Umfänge stehen!&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Datei:Formate_v2.png&amp;diff=9315</id>
		<title>Datei:Formate v2.png</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Datei:Formate_v2.png&amp;diff=9315"/>
		<updated>2025-07-04T07:21:56Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Das Fenster um Formate zu definieren&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Verf%C3%BCgbare_Funktionen&amp;diff=9305</id>
		<title>Verfügbare Funktionen</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Verf%C3%BCgbare_Funktionen&amp;diff=9305"/>
		<updated>2025-06-12T10:35:15Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3499: Doku für 2 neue Funktionen&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Die hier gelisteten Funktionen lassen sich bei allen Workflowschritten anwenden, welche einen Link zu dieser Seite besitzen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Funktionen==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beachte:&#039;&#039;&#039; Die Metadatumsfelder sind hier unbedingt als String (&#039;Metadatum&#039;) zu übergeben und nicht wie andersweitig in eckigen Klammern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===§getQuittungsFeld===&lt;br /&gt;
&lt;br /&gt;
Holt den Wert aus einem Quittungsfeld. Das Objekt muss dazu eine Quittung besitzen. Es wird immer auf die letzte erstellte Quittung zurückgegriffen. Aktuell werden Quittungsdetail im JSON Format unterstützt.&lt;br /&gt;
&lt;br /&gt;
Die Funktion erwartet einen gültigen Pfad zu einem JSON Member, oder anderst gesagt den Schlüssel zu einem Attribut in dem JSON. (JSON Pfade der Quittung finden: Siehe [[Warten auf Rückmeldung]])&lt;br /&gt;
&lt;br /&gt;
 §getQuittungsFeld(&#039;pfad.zu.dem.gewünschten.feld&#039;)&lt;br /&gt;
&lt;br /&gt;
===§istInWortliste===&lt;br /&gt;
&lt;br /&gt;
Ermittelt ob ein Metadatum in einer Wortliste vorkommt; wobei 1 = kommt vor, 0 = kommt nicht vor.&lt;br /&gt;
&lt;br /&gt;
Die Wortliste ist als [https://helper.ch/wiki/index.php?title=Konfiguration Konfigurationsdatensatz] zu erstellen. Der Name der erstellen Wortliste wird als Parameter zum finden der Liste benötigt.&lt;br /&gt;
&lt;br /&gt;
 §istInWortliste(Metadatumsname,Wortlistenname,Suchtyp,Zeilenumbruchtyp)&lt;br /&gt;
&lt;br /&gt;
;Metadatumsname: Wert des Metadatums, zB &#039;Eugen&#039; oder [Vorname]&lt;br /&gt;
;Wortlistenname: Name der Wortliste, also des Konfigurationsdatensatzes.&lt;br /&gt;
;Suchtyp: 0=Es wird genau nach dem Wert gesucht (Standard), 1=Findet auch &#039;Hans&#039;, wenn in der Wortliste &#039;Eugen Hans&#039; oder &#039;Hans-Peter&#039; steht&lt;br /&gt;
;Zeilenumbruchtyp: Welcher Zeilenumbruch wird in der Wortliste verwendet: 0=Zeilenumbruch ist &#039;CR&#039; (Standard), 1=Zeilenumbruch ist &#039;CRLF&#039;&lt;br /&gt;
&lt;br /&gt;
Bsp.: Es wurde eine Liste mit Vornamen in der Konfiguration erstellt. Diese Liste lautet auf den Namen &amp;quot;Vornamenkonfiguration&amp;quot;. Ein Metadatum &amp;quot;Vorname&amp;quot; wurde erstellt, dort wurden zuvor Vornamen gespeichert.&lt;br /&gt;
&lt;br /&gt;
 §istInWortliste(&#039;Vorname&#039;,&#039;Vornamenkonfiguration&#039;)&lt;br /&gt;
&lt;br /&gt;
===§getConfidenceOfWordInRegionXML===&lt;br /&gt;
&lt;br /&gt;
Gibt die vom OCR ermittelte Konfidenz zu einem gefundenen Begriff zurück und schreibt den Wert in ein Metadatum. Erlaubt optional die Angabe eines Einschräkungsbereiches, in welchem der gesuchte Begriff vorkommen muss.&lt;br /&gt;
&lt;br /&gt;
Der Bereich ist als Row(left,top,width,height) anzugeben: §getConfidenceOfWordInRegionXML(&#039;Suchwort&#039;,row(left,top,width,height))&lt;br /&gt;
&lt;br /&gt;
Bsp.:&lt;br /&gt;
 §getConfidenceOfWordInRegionXML(&#039;London&#039;,row(57,154,75,25))&lt;br /&gt;
&lt;br /&gt;
 0 = Begriff nicht gefunden&lt;br /&gt;
 0.1 - 100 = Konfidenz des gefundenen Begriffes&lt;br /&gt;
&lt;br /&gt;
===§istMin und §istMax===&lt;br /&gt;
&lt;br /&gt;
Vergleicht von DO Objekten die Attributswerte des angegebenen Attributs miteinander, und ermittelt ob das DO den grössten oder den kleinsten Wert der verglichenen Objekte besitzt. Alle DO Typen, welchen den gleichen Attributsnamen besitzen, werden für den Vergleich herbeigezogen.&amp;lt;br&amp;gt;&lt;br /&gt;
Die Hierarchiestufe der Objekte kann, ausgehend vom Objekt eingeschränkt werden.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pflicht: Metadatumsname, Hierarchieebene&amp;lt;br&amp;gt;&lt;br /&gt;
Optional: Metadatumsname2 (Ohne Metadatumsname2 werden allein die gefundenen Metadaten aus Metadatumsname verglichen, mit werden nur diejenigen Objekte welche den gleichen Wert in Metadatumsname2 haben verglichen).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 §istMax(Metadatumsname,Hierachieebene,Metadatumsname2)&lt;br /&gt;
 §istMax(Metadatumsname,../-2/-1/0/1/2/..,Metadatumsname2)&lt;br /&gt;
 §istMin(Metadatumsname,../-2/-1/0/1/2/..,Metadatumsname2)&lt;br /&gt;
 &lt;br /&gt;
 Bsp.:&lt;br /&gt;
 &#039;&#039;&#039;§istMax(&#039;AnzahlDok&#039;,1,&#039;Büronummer&#039;)&#039;&#039;&#039; Gibt 1 zurück, wenn das Objekt den grössten Wert im Attribut &#039;AnzahlDok&#039; hat, innerhalb der eigenen Tranche und der gleichen Büronummer. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameter&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 Metadatumsname: Der Name des Metadatums&lt;br /&gt;
 &lt;br /&gt;
 Hierachieebene: (Einschränkung)&lt;br /&gt;
 * 0 = Alle DO des Auftrages (=keine Einschränkung)&lt;br /&gt;
 * 1 = Alle DO mit dem selben Vorfahren auf Ebene 1 (typischerweise alle Objekte einer Tranche, inklusive der Tranche)&lt;br /&gt;
 * 2 = Alle DO mit dem selben Vorfahren auf Ebene 2&lt;br /&gt;
 * 3 = Alle DO mit dem selben Vorfahren auf Ebene 3&lt;br /&gt;
 * etc.&lt;br /&gt;
 * -1 = Alle auf der gleichen Ebene wie das DO Objekt, inklusive des Vorfahren &lt;br /&gt;
 * -2 = Alle 2 Ebenen höher als das DO Objekt&lt;br /&gt;
 &lt;br /&gt;
 Metadatumsname2: Schränkt die betrachteten Dos ein. Es werden nur die DO angesehen, die den gleichen Wert im Attribut &#039;&#039;&#039;Metadatumsname2&#039;&#039;&#039; haben.&lt;br /&gt;
&lt;br /&gt;
===§sortierung===&lt;br /&gt;
&lt;br /&gt;
Gibt die Sortierreihenfolge des Objektes zurück. Analog zu verwenden wie $min/$max. &lt;br /&gt;
&lt;br /&gt;
 §sortierung(Metadatumsname,../-2/-1/0/1/2/.., Metadatumsname2,0/1)&lt;br /&gt;
&lt;br /&gt;
 Bsp:&lt;br /&gt;
 §sortierung(&#039;Büronummer&#039;,-1,&#039;Metadatumsname2&#039;,0)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameter&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 Metadatumsname: Der Name des Metadatums&lt;br /&gt;
 &lt;br /&gt;
 Hierachieebene: (Einschränkung)&lt;br /&gt;
 * 0 = Alle DO des Auftrages (=keine Einschränkung)&lt;br /&gt;
 * 1 = Alle DO mit dem selben Vorfahren auf Ebene 1 (typischerweise alle Objekte einer Tranche, inklusive der Tranche)&lt;br /&gt;
 * 2 = Alle DO mit dem selben Vorfahren auf Ebene 2&lt;br /&gt;
 * 3 = Alle DO mit dem selben Vorfahren auf Ebene 3&lt;br /&gt;
 * etc.&lt;br /&gt;
 * -1 = Alle auf der gleichen Ebene wie das DO Objekt, inklusive des Vorfahren &lt;br /&gt;
 * -2 = Alle 2 Ebenen höher als das DO Objekt&lt;br /&gt;
 &lt;br /&gt;
Metadatumsname2: Schränkt die betrachteten Dos ein. Es werden nur die DO angesehen, die den gleichen Wert im Attribut &#039;&#039;&#039;Metadatumsname2&#039;&#039;&#039; haben.&lt;br /&gt;
  &lt;br /&gt;
 Sortierreihenfolge: 0 = Aufwärts, 1 = Abwärts&lt;br /&gt;
&lt;br /&gt;
===§istEindeutig===&lt;br /&gt;
&lt;br /&gt;
Prüft ob für ein DO Objekt ein bestimmtes Metadatum im Vergleich zu weiteren DOs eindeutig ist. Vergleiche sind mit DOs auf wählbarer Hierarchieebene sowie mit gleichem oder abweichendem DO Typ möglich.&lt;br /&gt;
&lt;br /&gt;
 §istEindeutig(Metadatumsname, 0/1/2, 0/1/2[,DO Typen])&lt;br /&gt;
 §istEindeutig(Metadatumsname, Hierarchieebene, Typ-Einschränkung[,&#039;Typ1,Typ2,..&#039;])&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parameter&#039;&#039;&#039;&lt;br /&gt;
 Metadatumsname: Der Name des Metadatums&lt;br /&gt;
 Bereich: 0 = Ganzer Auftrag, alle DO dieses Auftrages, 1 =  Alle DO auf Ebene 1, 2 = Alle DO auf Ebene 2&lt;br /&gt;
 Typ-Einschränkung: 0 = Alle Typen mit dem gleichen Metadatumsname, 1 = Gleicher Typ wie das Vergleichsobjekt, 2 = Alle im zwingend folgenden Parameter angegebenen Typen&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Anwendung&#039;&#039;&#039;&lt;br /&gt;
 §istEindeutig(&#039;Verlag&#039;,0,0) Alle DO des Auftrages, welche bei einem beliebiegen DO Typ und dem Attribut &#039;Verlag&#039; das selbe Metadatum besitzen&lt;br /&gt;
 §istEindeutig(&#039;Verlag&#039;,1,1) Alle DO auf Ebene 1, welche zum gleichen Typ und dem Attribut &#039;Verlag&#039; das selbe Metadatum besitzen&lt;br /&gt;
 §istEindeutig(&#039;Verlag&#039;,2,0) Alle DO auf Ebene 2, welche bei einem beliebiegen Typ und dem Attribut &#039;Verlag&#039; das selbe Metadatum besitzen&lt;br /&gt;
 §istEindeutig(&#039;Verlag&#039;,2,1) Alle DO auf Ebene 2, welche zum gleichen Typ und dem Attribut &#039;Verlag&#039; das selbe Metadatum besitzen&lt;br /&gt;
 §istEindeutig(&#039;Verlag&#039;,2,2,&#039;Buch, Magazin, Zeitung&#039;) Alle DO auf Ebene 2, welche zu den angegebenen Typen &#039;Buch, Magazin, Zeitung&#039; und dem Attribut &#039;Verlag&#039; das selbe Metadatum besitzen&lt;br /&gt;
&lt;br /&gt;
Fehleingabe vermeiden:&lt;br /&gt;
 §istEindeutig(&#039;Verlag&#039;,2,2) Es wird eine Typeinschränkung (Parameter drei = 2) verlangt, ohne nachfolgende die gesuchten Typen zu nennen.&lt;br /&gt;
&lt;br /&gt;
===§KindNr===&lt;br /&gt;
&lt;br /&gt;
Diese Methode gibt zurück, das wievielte Kind das Objekt ist. &lt;br /&gt;
&lt;br /&gt;
 §KindNr()&lt;br /&gt;
&lt;br /&gt;
 Bsp: &lt;br /&gt;
 Das Objekt hat 5 Geschwister und ist als viertes erstellt worden. Somit gibt die Methode §KindNr 4 zurück.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===§sortierungSignatur===&lt;br /&gt;
&lt;br /&gt;
Diese Methode gibt zurück, die Position des Objektes von allen Objekten mit der gleichen Signatur.&lt;br /&gt;
&lt;br /&gt;
 §sortierungSignatur()&lt;br /&gt;
&lt;br /&gt;
 Bsp: &lt;br /&gt;
 Gegeben:&lt;br /&gt;
 Objekt 1 mit Signatur &#039;A&#039;&lt;br /&gt;
 Objekt 2 mit Signatur &#039;B&#039;&lt;br /&gt;
 Objekt 3 mit Sigantur &#039;A&#039;&lt;br /&gt;
 Objekt 4 mit Signatur &#039;A&#039;&lt;br /&gt;
 Objekt 5 mit Signatur &#039;C&#039;&lt;br /&gt;
 &lt;br /&gt;
 Wird zurückgegeben: &lt;br /&gt;
 Objekt 1 -&amp;gt; 1 (weil es das erste Objekt ist mit Signatur &#039;A&#039;)&lt;br /&gt;
 Objekt 2 -&amp;gt; 1 (weil es das erste Objekt ist mit Signatur &#039;B&#039;)&lt;br /&gt;
 Objekt 3 -&amp;gt; 2 (weil es das zweite Objekt ist mit Signatur &#039;A&#039;)&lt;br /&gt;
 Objekt 4 -&amp;gt; 3 (weil es das dritte Objekt ist mit Signatur &#039;A&#039;)&lt;br /&gt;
 Objekt 5 -&amp;gt; 1 (weil es das erste Objekt ist mit Signatur &#039;C&#039;)&lt;br /&gt;
&lt;br /&gt;
===§minX===&lt;br /&gt;
&lt;br /&gt;
Bevor diese Methode ausgeführt werden kann, muss der Schritt [[Files messen]] gemacht werden.&lt;br /&gt;
Diese Methode gibt die kleinstmögliche Breite des Objektes nachdem die [[Files messen|Files gemessen]] wurden an, grösser oder gleich dem Parameter.&lt;br /&gt;
Es werden alle Files ausgewertet ausser PDFs.&lt;br /&gt;
Die Methode erwartet eine Zahl als Pixel-Wert.&lt;br /&gt;
&lt;br /&gt;
 §minX(minimumPixel)&lt;br /&gt;
&lt;br /&gt;
 Bsp:&lt;br /&gt;
 Objekt mit folgenden Files: auto.jpg (Breite: 100), baum.jpg (Breite:200), clown.jpg (Breite:110)&lt;br /&gt;
 Methode §minX(105) gibt 110 zurück&lt;br /&gt;
 Methode §minX(110) gibt 110 zurück&lt;br /&gt;
 Methode §minX(150) gibt 200 zurück&lt;br /&gt;
&lt;br /&gt;
===§minY===&lt;br /&gt;
&lt;br /&gt;
Bevor diese Methode ausgeführt werden kann, muss der Schritt [[Files messen]] gemacht werden.&lt;br /&gt;
Diese Methode gibt die kleinstmögliche Höhe des Objektes nachdem die [[Files messen|Files gemessen]] wurden an, grösser oder gleich dem Parameter.&lt;br /&gt;
Es werden alle Files ausgewertet ausser PDFs.&lt;br /&gt;
Die Methode erwartet eine Zahl als Pixel-Wert.&lt;br /&gt;
&lt;br /&gt;
 §minY(minimumPixel)&lt;br /&gt;
&lt;br /&gt;
 Bsp:&lt;br /&gt;
 Objekt mit folgenden Files: auto.jpg (Höhe: 100), baum.jpg (Höhe:200), clown.jpg (Höhe:110)&lt;br /&gt;
 Methode §minY(105) gibt 110 zurück&lt;br /&gt;
 Methode §minY(110) gibt 110 zurück&lt;br /&gt;
 Methode §minY(150) gibt 200 zurück&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===§OCRTextRegion===&lt;br /&gt;
&lt;br /&gt;
Führt OCR auf einer bestimmen Seitennummer (einzelne Bild Datei!) in einer bestimmten Region aus, und gibt als Resultat den gefundenen Text zurück. Dieser Text lässt sich dann z.B. in ein Metadatum übertragen.&lt;br /&gt;
&lt;br /&gt;
Die Seitennummer wird über die Sortierreihenfolge der Dateinamen im Dateisystem bestimmt. Es werden TIFF, JPG und PNG als Dateiformate unterstützt.&lt;br /&gt;
&lt;br /&gt;
Die wählbare Region, welche eine rechteckige Selektion ist, wird über die Koordinaten X1,X2,Y1,Y2 in Pixel definiert. Wobei X1=linker Rand, X2=rechter Rand, Y1=oberer Rand, Y2=unterer Rand.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wenn für die Koordinaten negative Werte eingesetzt werden, so werden die Positionen relativ zur Bildgrösse und ausgehend vom rechten oder unteren Bildrand berechnet!&#039;&#039;&#039;&lt;br /&gt;
 &lt;br /&gt;
 §OCRTextRegion(Seite,X1,X2,Y1,Y2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bsp: Seite Nummer 5 (entspricht Datei Nummer 5). Bilddimensionen: 2663 Breite x 3603 Höhe&lt;br /&gt;
&lt;br /&gt;
 §OCRTextRegion(5,359,709,631,690)  -&amp;gt; entspricht einem Auswahlrechteck mit Abstand Links=359, Abstand oben=631, Breite=350, Höhe=59&lt;br /&gt;
&lt;br /&gt;
 §OCRTextRegion(5,-2304,709,-2972,690)  -&amp;gt; entspricht genau dem gleichen Auswahlrechteck mit Abstand Links=359, Abstand oben=631, Breite=350, Höhe=59 &#039;&#039;&#039; weil das Bild die gleiche Dimension besitzt!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 §OCRTextRegion(5,-2304,-1954,-2972,-2913)  -&amp;gt; entspricht genau dem gleichen Auswahlrechteck mit Abstand Links=359, Abstand oben=631, Breite=350, Höhe=59 &#039;&#039;&#039;weil das Bild die gleiche Dimension besitzt!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===§FileAnzahl===&lt;br /&gt;
&lt;br /&gt;
Diese Methode gibt dir Anzahl Dateien am aktuellen Datenschritt des Objektes zurück. Dabei werden alle Dateien auch in allen Unterordnern gezählt. Unsichtbare Dateien sowie die Ordner selbst zählen nicht.&lt;br /&gt;
&lt;br /&gt;
 §FileAnzahl()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===§Hausnummer===&lt;br /&gt;
Diese Methode formatiert einen Hausnummer.&lt;br /&gt;
 §Hausnummer(Wert)&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
 12 -&amp;gt; 012&lt;br /&gt;
 123 -&amp;gt; 123&lt;br /&gt;
 12a -&amp;gt; 012a&lt;br /&gt;
 2a -&amp;gt; 002a&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===§KinderSummeAT===&lt;br /&gt;
Gibt die Summe der Werte des Attributs aller Kinder zurück, nicht rekursiv, also nur der direkten Kinder.&lt;br /&gt;
 §KinderSummeAT(&#039;Attribut&#039;)&lt;br /&gt;
&lt;br /&gt;
===§KinderWertAT===&lt;br /&gt;
Gibt den Wert des Attributs des ersten Kindes zurück. Idealerweise hat es nur ein Kind. Sonst wir das erste genommen.&lt;br /&gt;
 §KinderWertAT(&#039;Attribut&#039;)&lt;br /&gt;
&lt;br /&gt;
===§isJSONValid===&lt;br /&gt;
Prüft ob ein Attribut ein valides JSON ist. Gibt Wahr (true) oder Falsch (false) zurück.&lt;br /&gt;
 §isJSONValid(&#039;JSON&#039;)&lt;br /&gt;
&lt;br /&gt;
===§StrasseAusschreiben===&lt;br /&gt;
Diese Methode prüft ob ein Strassennamen (mit oder ohne Hausnummer) schön formatiert ist. Dabei wird jeder Anfangsbuchstabe in einen Grossbuchstaben geändert. &amp;quot;str&amp;quot; und &amp;quot;str.&amp;quot; werden zu &amp;quot;strasse&amp;quot; ausgeschrieben.&lt;br /&gt;
&lt;br /&gt;
 §StrasseAusschreiben(&#039;Strasse&#039;)&lt;br /&gt;
&lt;br /&gt;
====Beispiele====&lt;br /&gt;
  Teststr 58A =&amp;gt; Teststrasse 58A&lt;br /&gt;
  zUr lindENstr. =&amp;gt; Zur Lindenstrasse&lt;br /&gt;
  Hofweg 68 =&amp;gt; Hofweg 68 &lt;br /&gt;
&lt;br /&gt;
==Weitere Beispiele==&lt;br /&gt;
 §OCRMatchCount(&#039;Bericht&#039;)&amp;gt;0 ==&amp;gt; Falls das Wort Bericht mindestens 1 Mal gefunden wurde ist der Ausdruck wahr&amp;lt;br&amp;gt;&lt;br /&gt;
 §OCRMatchCount(&#039;[0-9][0-9][.]&#039;)=0 ==&amp;gt; Falls KEINE 2 stellige Zahl mit einem Punkt gefunden wird ist der Ausdruck wahr&amp;lt;br&amp;gt;&lt;br /&gt;
 §OCRMatchCount(&#039;[BelegName]&#039;)&amp;gt;2 ==&amp;gt; Falls der Wert des Attributes BelegName mehr als 2 mal gefunden wird ist der Ausdruck wahr&amp;lt;br&amp;gt;&lt;br /&gt;
 §OCRMatchCount(&#039;[BelegName]&#039;,1)&amp;gt;0 ==&amp;gt; Falls der Wert des Attributes BelegName mindestens einmal im OCR der Kindern gefunden wurde.&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Objekt_Umwandlung/Verdoppelung&amp;diff=9288</id>
		<title>Objekt Umwandlung/Verdoppelung</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Objekt_Umwandlung/Verdoppelung&amp;diff=9288"/>
		<updated>2025-05-07T07:27:16Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3503: Wiki ergänzt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  1824,  2662&lt;br /&gt;
;Systemtyp: &lt;br /&gt;
  21&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
Besteht aus einem Serverjob OJOHZDOVerdoppeln. &lt;br /&gt;
&lt;br /&gt;
Erzeugt eine Kopie (Duplikat) eines DO Objektes, optional mit &lt;br /&gt;
* den zugehörigen Dateien&lt;br /&gt;
* den zugehörigen Metadaten&lt;br /&gt;
&lt;br /&gt;
Das erzeugte Duplikat geht zum Herstellungsschritt HZ_HZ_SEQ2. Das Original zu HZ_HZ_SEQ. Folgende Fehler werden beim Duplikat gelöscht: Fehlertext, FTPUPLOADFiles, Änderungsdatum. Das Erfassungsdatum wird auf heute gestellt.&lt;br /&gt;
&lt;br /&gt;
Umgangssprachlicher Name: Objekte duplizieren.&lt;br /&gt;
&lt;br /&gt;
Es ist möglich die Daten vom aktuellen Datenschritt oder einem spezifischen Datenschritt zu duplizieren. Falls Sie einen spezifischen Datenschritt angeben und bei einem DO keine Daten gefunden werden gibt es einen Fehler.&lt;br /&gt;
&lt;br /&gt;
==Objekt Erstellen bei Bildgrössenveränderung==&lt;br /&gt;
In diesem Modus wird das Haupt DO so oft dupliziert wie es Bildgrössenveränderungen (+- 1cm in Höhe und Breite zum vorherigen File) gibt. zB A4, A4, A3, A3, A4 gibt 2 neues DOs mit den Files A3, A3 und A4. Die Dateien werden in das duplizierte DO verschoben. &lt;br /&gt;
&lt;br /&gt;
Wenn die Checkbox &amp;quot;Einzelnes Objekt erstellen wenn Bild grösser ist als Grenzwert&amp;quot; markiert wird, werden alle Dateien welche grösser sind zu einem Single Page Objekt. zB aus A4, A4, A3, A3, A4 werden 3 neue DOs A3 und A3 und A4.&lt;br /&gt;
&lt;br /&gt;
Beachten Sie beim Grenzmass, dass nicht alle Scans gleich gross sind und geben Sie entsprechende Marge. Das DO muss natürlich vorher durch einen Filemessen Schritt laufen.&lt;br /&gt;
&lt;br /&gt;
==Essentielle Felder==&lt;br /&gt;
  &lt;br /&gt;
  HZ_FILEVERHALTEN: 0=Duplikat erhält keine Files, 1=Duplikat erhält Kopien der Files&lt;br /&gt;
  HZ_METADATENERFASSEN: 0=Duplikat erhält keine Metadaten, 1=Duplikat erhält Metadaten&lt;br /&gt;
  HZ_DELEATUR: HZ_SEQ des Datenschrittes von welchem die Daten dupliziert werden sollen&lt;br /&gt;
  Aktuell nicht mehr verwendet - HZ_KINDERVERDOPPELN 0=nein 1=eine Ebene 2=zwei Ebenen etc&lt;br /&gt;
  HZ_EXPORTFILETYP: Neues Objekt erstellen bei Bildgrössenveränderung&lt;br /&gt;
  HZ_HASHTYP: Einzelnes Objekt (Single Page) erstellen wenn Bild grösser ist als Grenzmass&lt;br /&gt;
  HZ_RANDOBENHINZU: Breite des Grenzmass&lt;br /&gt;
  HZ_RANDLINKSHINZU: Höhe des Grenzmass &lt;br /&gt;
&lt;br /&gt;
  DO_DO_SEQ2 Verknüpfung zum Originalobjekt vor der Verdoppelung&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Metadaten_mit_Anzeige_des_Files&amp;diff=9274</id>
		<title>Metadaten mit Anzeige des Files</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Metadaten_mit_Anzeige_des_Files&amp;diff=9274"/>
		<updated>2025-04-03T07:26:23Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3461: Superusermode ergänzt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  1980&lt;br /&gt;
;Systemtyp: &lt;br /&gt;
  31&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
Einer der Arbeitsschritte (FDO_SHZTyp31), welcher im Fenster FDO_Auswahl1 ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
In diesem Arbeitsschritt werden Metadaten zu den jeweiligen Objekt erfasst.&lt;br /&gt;
&lt;br /&gt;
Es gibt vier verschiedene Fenster:&lt;br /&gt;
* Eines ist generell&lt;br /&gt;
* Eines ist angepasst an Zeitungsartikel (b)&lt;br /&gt;
* Eines ist angepasst an den Murdockcode (a)&lt;br /&gt;
* Eines ist angepasst an die Denkmalpflege (c)&lt;br /&gt;
* Eines ist angepasst an für die Anzeige von Geschwister und Vater (d)&lt;br /&gt;
* Eines ist angepasst an das Projekt Badischer Bahnhof (e)&lt;br /&gt;
* Eines ist angepasst für OCR (f)&lt;br /&gt;
* Eines ist angepasst an die Einwohnerkarten (g)&lt;br /&gt;
* Eines ist angepasst an die Azure-Validierung (h)&lt;br /&gt;
&lt;br /&gt;
Es können X beliebige Ausgänge für den User aus den Metadatierungsfenstern definiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Leistungen===&lt;br /&gt;
Alle Metadaten werden vor dem Starten des Schrittes mit denen am Ende verglichen. Es können folgenden Leistungen vorkommen:&lt;br /&gt;
;Felder, Create: Wie viele Metadaten wurden neu erfasst.&lt;br /&gt;
;Felder, Update: Wie viele Metadaten wurden aktualisiert.&lt;br /&gt;
;Felder, Delete: Wie viele Metadaten wurden gelöscht.&lt;br /&gt;
&lt;br /&gt;
==Essentielle Felder==&lt;br /&gt;
;Daten vom Server holen: Muss angekreuzt sein, sonst werden die Bilder des Objektes nicht angezeigt.&lt;br /&gt;
;Nächster Arbeitsschritt im normalen Fall: Nummer des Arbeitsschrittes, an den Objekte gehen, wenn alles ok ist. (HZ_HZ_SEQ1)&lt;br /&gt;
&lt;br /&gt;
==Pane im Produktionsauftrag (FHK_Maske)==&lt;br /&gt;
&lt;br /&gt;
[[File:FHZ STyp31.png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;br /&gt;
&lt;br /&gt;
==Spezifische Konfiguration Denkmalpflege==&lt;br /&gt;
* Untersystemtyp = FDO_Auswahl1:FDO_SHZTyp31c:FAA_SMaske31c:DENKINF&lt;br /&gt;
* Daten nicht vom Server holen (Werden ja nicht bearbeitet)&lt;br /&gt;
* Metadatenerfassen = Ja&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Attribute für den Objekttyp &amp;quot;Bild&amp;quot;===&lt;br /&gt;
Diese Attribute müssen zwingend genau so erfasst werden:&amp;lt;br&amp;gt;&lt;br /&gt;
bezeichnung, plz, ort, strasse, hausnummer, hausnummerzusatz, parzelle, objekttyp, &amp;lt;br&amp;gt;&lt;br /&gt;
baujahr, rrbnr, objid, bildtyp, code, beschreibung, sujet, jahr, ersteller, bemerkungen&lt;br /&gt;
&lt;br /&gt;
===Sonnstiges===&lt;br /&gt;
Der AT an welchem alle AOs hängen, welche vom Excel importiert wurden, hängt an keinem HK. Es ist ein Standalone AT und für die Zukunft wiederverwendbar.&lt;br /&gt;
&lt;br /&gt;
==Spezifisches Fenster für Azure-Validierung (h)==&lt;br /&gt;
In diesem Fenster lassen sich Metadaten, welcher vorher mit Azure ausgelesen wurden, kontrollieren und korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Serverjob Konfiguration===&lt;br /&gt;
* Konfigurieren Sie, welche Metadaten angezeigt werden. Sie können definieren, wie viele Zeilen das Eingabefeld im Fenster haben soll.&lt;br /&gt;
* Stellen Sie sicher, dass das Metadatum, in welchem das JSON gespeichert ist, ausgeblendet ist.&lt;br /&gt;
* Geben Sie den Namen des Metadatum an, in welchem sich das Azure JSON befindet.&lt;br /&gt;
&lt;br /&gt;
===Arbeitsfenster===&lt;br /&gt;
* In diesem Fenster kann der Angestellte die Metadatenwerte prüfen&lt;br /&gt;
* Vor dem Abschluss des Objektes, muss er alle Seiten angeschaut haben, sofern Sie das Konfiguriert haben&lt;br /&gt;
* Der Cursor springt automatisch in das erste Feld mit einer roten Confidence&lt;br /&gt;
* Mit Tab springt der Cursor direkt ins nächste rote Feld&lt;br /&gt;
* Es werden grüne oder orange Rahmen um den Begriff auf der PDF-Anzeige gezeichnet&lt;br /&gt;
&lt;br /&gt;
=== Super User Mode ===&lt;br /&gt;
* Sie können in den Produktionsaufträgen unter Diverses für bestimmte Angestellte den &amp;quot;Superusermode&amp;quot; einschalten&lt;br /&gt;
* Dadurch wird unter jedem Eingabefeld ein Text in der Form FKG XX/XX, FKNG XX/XX, OCR XX/XX angezeigt&lt;br /&gt;
* FKG zeigt die Feldkonfidenz gefunden an&lt;br /&gt;
* FKNG zeigt die Feldkonfidenz nicht gefunden an&lt;br /&gt;
* OCR zeigt die Konfidenz des ausgelesenen Textes an&lt;br /&gt;
&lt;br /&gt;
[[Datei:FDOSHZTyp31h(2).png|800px]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Datei:FDOSHZTyp31h(2).png&amp;diff=9273</id>
		<title>Datei:FDOSHZTyp31h(2).png</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Datei:FDOSHZTyp31h(2).png&amp;diff=9273"/>
		<updated>2025-04-03T07:22:55Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Azure Kontrollfenster&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Filetest&amp;diff=9206</id>
		<title>Filetest</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Filetest&amp;diff=9206"/>
		<updated>2025-03-13T10:03:31Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3459: Wiki erweitert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  1526&lt;br /&gt;
&lt;br /&gt;
  1822&lt;br /&gt;
;Systemtyp: &lt;br /&gt;
  18&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
Besteht aus einem Serverjob OJOHZDOFiletest. Überprüft die Files auf ihre Richtigkeit. Das Ergebnis (0/1) kann in einem Attribut gespeichert werden. Falls ein Test fehlschlägt geht das Objekt zu zum roten Ausgang und im Fehlertext steht, welche Bedingung(en) nicht erfüllt wurde(n).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Grundsätzlich sind hier keine Formeln für die Werte möglich, mit Ausnahme:&#039;&#039;&#039; &#039;&#039;FileAnzahl&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Konfiguration FileAnzahl===&lt;br /&gt;
Bei diesem Test werden die &#039;&#039;&#039;Dateien und Ordner&#039;&#039;&#039; im auf oberster Ebene im Objektordner gezählt. Die Dateien in (Unter-)Ordnern zählen nicht. Der Ordner &#039;Hilfsobjekte&#039; zählt auch.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Zugriff auf Metadaten des Objektes, bzw. das einsetzen von Formel sind für diesen Test erlaubt.&#039;&#039;&#039; &#039;&#039;Das Metadatum ist wie üblich in eckigen Klammern zu nennen: [MetadatumMitAnzahl]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Konfiguration FileTyp===&lt;br /&gt;
Bei diesem Test wird jedes File im Objektordner mit konfigurierten Filetyp verglichen. Ordner werden (natürlich) nicht verglichen. Files in Unterordnern werden nur getestet, wenn &#039;Rekursiv&#039; angekreuzt ist. &lt;br /&gt;
&lt;br /&gt;
===Konfiguration BildformatXY===&lt;br /&gt;
Bei diesem Test können beide Seiten des Bildformats (X und Y) berücksichtigt werden.&lt;br /&gt;
*Operator Codes können sein (&amp;gt;, *&amp;gt;, &amp;gt;&amp;gt;, *&amp;gt;&amp;gt;) Bzw. die Varianten für kleiner (&amp;lt;) und gleich (=)&lt;br /&gt;
*&amp;gt;,= wenn eine Seite grösser/gleich als ihr entsprechender Maximalwert (xi &amp;gt; xs) | (yi &amp;gt; ys)&lt;br /&gt;
*&amp;gt;&amp;gt;,== wenn beide Seiten grösser / gleich wie der entsprechende Maximalwert (xi &amp;gt; xs) &amp;amp; (yi &amp;gt; ys)&lt;br /&gt;
* *&amp;gt;, *= wenn mindestens eine beliebige Seite grösser / gleich ist wie ein beliebiger Maximalwert&lt;br /&gt;
* *&amp;gt;&amp;gt;, *== wenn je beide Seiten grösser / gleich wie ein beliebiger Maximalwert sind (Bildausrichtung gleich oder gedreht)&lt;br /&gt;
Der Vergleichswert wird geschrieben: 2000x3000&lt;br /&gt;
&lt;br /&gt;
===Konfiguration Farbraum===&lt;br /&gt;
Bei diesem Test wird der Farbraum aus dem File gelesen. Typische Werte sind &#039;Gray&#039; oder &#039;sRGB&#039;. Bitte achten Sie auf Grosskleinschreibung.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration Positions SW Histogramm ===&lt;br /&gt;
Bei diesem Test wird ein Histogramm in einem PDF / Bild generiert basierend auf einer bestimmten Position sowie einem Grössenbereich.&lt;br /&gt;
Grundsätzlich wird immer von links oben aus gerechnet.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
1. Parameter = Seite - zB 4 (Wird nur bei PDF&#039;s verwendet)&amp;lt;br&amp;gt;&lt;br /&gt;
2. Parameter = Position X - zB 250 oder -150 (Bei Bildern in Pixel, bei PDF&#039;s in mm / Negative Zahlen werden von Rechts statt Links aus gerechnet)&amp;lt;br&amp;gt;&lt;br /&gt;
3. Parameter = Position Y - zB 300 oder - 200 (Bei Bildern in Pixel, bei PDF&#039;s in mm / Negative Zahlen werden von Unten statt Oben aus gerechnet)&amp;lt;br&amp;gt;&lt;br /&gt;
4. Parameter = Breite - zB 500 oder 25 % (Entweder Prozentangabe oder bei Bildern in Pixel, bei PDF&#039;s in mm)&amp;lt;br&amp;gt;&lt;br /&gt;
5. Parameter = Höhe - zB 200 oder 15 % (Entweder Prozentangabe oder bei Bildern in Pixel, bei PDF&#039;s in mm)&amp;lt;br&amp;gt;&lt;br /&gt;
6. Parameter = Helligkeitsgrenzwert - zB 150 (Werte von 0 - 255, wobei 0=Schwarz / 255 = Weiss)&amp;lt;br&amp;gt;&lt;br /&gt;
7. Parameter = Prozent - zB 35% (Wie viel Prozent der Pixel müssen über oder unter der angegeben Helligkeit sein)&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Hier ein komplettes Beispiel: &amp;quot;1,100,-150,140,5%,200,30%&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
*Es wird Seite 1 gemessen (falls es um ein PDF geht)&lt;br /&gt;
*Es wird der folgende Bildausschnitt genommen: Annahme das Bild ist 1000x500px gross&lt;br /&gt;
** Linke obere Ecke: 100/350 px. (350=500-150)&lt;br /&gt;
** Grösse des Ausschnitts: 140x25 px. (25=5% von 500)&lt;br /&gt;
** Rechte untere Ecke: 240/375 px.&lt;br /&gt;
*Es wird folgende Formel evaluiert:&lt;br /&gt;
  (Pixelheller (als Grauwert 200) / TotaleAnzahlPixel) &amp;gt; oder &amp;lt; Prozent (30%).&lt;br /&gt;
Es werden also immer die helleren Pixel als der Helligkeitsgrenzwert gezählt und durch die totale Anzahl Pixel geteilt. Das Ergebnis wird mit dem Prozentsatz verglichen.&lt;br /&gt;
Falls ein Wert nicht angegeben werden soll muss das Komma dennoch da stehen. Beispiel ohne die Angabe der Seite: &amp;quot;,100,-150,140,5%,200,30%&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
==== Beispiele Bildausschnitt====&lt;br /&gt;
* Das ganze Bild (Seite 1) soll gemessen werden: &amp;quot;1,1,1,100%,100%...&amp;quot;&lt;br /&gt;
* Links oben in der Ecke soll ein Quadrat von 100px gemessen werden: &amp;quot;1,1,1,100,100...&amp;quot;&lt;br /&gt;
==== Beispiele Helligkeit====&lt;br /&gt;
* Es darf fast keine (fast) schwarzen Pixel haben: &amp;gt; &amp;quot;...20, 98%&amp;quot; -&amp;gt; mehr als 98% der Pixel sollen heller sein als fast schwarz (Grauwert 20)&lt;br /&gt;
* Es soll fast ganz weiss sein: &amp;gt; &amp;quot;...240, 99%&amp;quot; -&amp;gt; 99% der Pixel sollen heller als der Grauwert 240 sein (fast weiss)&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration Ist Extrem ===&lt;br /&gt;
Bei diesem Test wird jedes DO geprüft ob es nach der konfigurierten Weise extrem ist.&lt;br /&gt;
&lt;br /&gt;
1. Parameter = Sortierfeld - Dieser Wert wird aufs &amp;quot;Extrem sein&amp;quot; geprüft. Muss ein AT-Name sein&amp;lt;br&amp;gt;&lt;br /&gt;
2. Parameter = Selektionsfeld - Es werden nur DOs berücksichtig die den gleichen Wert im Selektionsfeld haben wie das DO welches gerade angeschaut wird. Muss ein AT-Name sein. Falls leer wird DO_DO_SEQ automatisch verwendet.&amp;lt;br&amp;gt;&lt;br /&gt;
3. Parameter = Menge - Ab wann wird ein DO als Extrem beachtet? zB. 10&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Hier ein komplettes Beispiel: &amp;quot;seitenanzahl,pdfname,10&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
Ist das DO in den Top 10 mit den Seitenzahlen verglichen mit allen DOs welche denselben PDF Namen haben?&lt;br /&gt;
&lt;br /&gt;
===Konfiguration Pixeltiefe pro Kanal===&lt;br /&gt;
Bei diesem Test wird die Anzahl Pixel pro Kanal aus dem File gelesen. Typische Werte sind 8 oder 16.&lt;br /&gt;
&lt;br /&gt;
===Konfiguration ICC Profile===&lt;br /&gt;
Bei diesem Test wird aus dem File die Zeile icc:description gefiltert und der Text danach herausgelesen. Ein typischer Wert ist &#039;Adobe RGB (1998)&#039;.&lt;br /&gt;
&lt;br /&gt;
Sie können das Feld bei einem Bild auch auslesen:&lt;br /&gt;
  identify -verbose &amp;quot;Pfad zum Bild&amp;quot;&lt;br /&gt;
Suchen Sie nach der Zeile &#039;icc:description&#039;&lt;br /&gt;
&lt;br /&gt;
===Dateigrösse===&lt;br /&gt;
&lt;br /&gt;
Bei diesem Test wird eine Dateigrösse in Bytes geprüft.&lt;br /&gt;
&lt;br /&gt;
Operator Codes können sein (&amp;gt;,&amp;lt;).&lt;br /&gt;
&lt;br /&gt;
===SeitenAnzahl===&lt;br /&gt;
&lt;br /&gt;
Bei diese Test wird die Anzahl Seiten in einem PDF oder TIFF Dokument geprüft. &lt;br /&gt;
&lt;br /&gt;
Operator Codes können sein (&amp;gt;,&amp;lt;,=,&amp;lt;&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==Allgemeine Metadaten von Bildformaten==&lt;br /&gt;
&lt;br /&gt;
Für die unten folgenden Konfigurationen kann für die gesuchten Werte auf diese Auflistungen von TAG Namen zurückgegriffen werden: &lt;br /&gt;
&lt;br /&gt;
[https://www.exiftool.org/TagNames/ TAG Übersicht]&lt;br /&gt;
&lt;br /&gt;
[https://www.exiftool.org/TagNames/EXIF.html EXIF Tags]&lt;br /&gt;
&lt;br /&gt;
[https://www.exiftool.org/TagNames/IPTC.html IPTC Tags]&lt;br /&gt;
&lt;br /&gt;
[https://www.exiftool.org/TagNames/XMP.html XMP Tags]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Suche nach leeren Tags&#039;&#039;&#039;&lt;br /&gt;
 &lt;br /&gt;
Falls nach leeren, bzw. fehlenden Werten gesucht werden soll, dann ist der Wertebereicht nach dem Komma leer zu lassen.&lt;br /&gt;
&lt;br /&gt;
Bsp.: Kein Änderungsdatum vorhanden&lt;br /&gt;
&lt;br /&gt;
[[Datei:Metadatum Datum leer.png]] &lt;br /&gt;
&lt;br /&gt;
===Konfiguration Metadatum Text===&lt;br /&gt;
&lt;br /&gt;
Bei diesem Test wird ein TAG mit Textinhalt verglichen.&lt;br /&gt;
&lt;br /&gt;
Operator Codes können sein (=, &amp;lt;&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
Bsp.: Gesucht wird der Hersteller des Aufnahmegerätes. Der entsprechende TAG heisst &#039;Make&#039;. Der gesuchte Wert soll auf &#039;Canon&#039; lauten.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Metadatum Text.png]]&lt;br /&gt;
&lt;br /&gt;
===Konfiguration Metadatum Zahl===&lt;br /&gt;
&lt;br /&gt;
Bei diesem Test wird ein TAG mit Zahleninhalt verglichen.&lt;br /&gt;
&lt;br /&gt;
Operator Codes können sein (=, &amp;lt;&amp;gt;, &amp;gt;, &amp;gt;=, &amp;lt;, &amp;lt;=)&lt;br /&gt;
&lt;br /&gt;
Bsp.: Gesucht wird nach der X Auflösung des Bildes. Der entsprechende TAG heisst &#039;XResolution&#039;. Der gesuchte Wert soll grösser oder gleich 3500 sein.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Metadatum Zahl.png]]&lt;br /&gt;
&lt;br /&gt;
===Konfiguration Metadatum Datum===&lt;br /&gt;
&lt;br /&gt;
Bei diesem Test wird ein TAG mit Datumsinhalt verglichen.&lt;br /&gt;
&lt;br /&gt;
Operator Codes können sein (=, &amp;lt;&amp;gt;, &amp;gt;, &amp;gt;=, &amp;lt;, &amp;lt;=)&lt;br /&gt;
&lt;br /&gt;
Bsp.: Gesucht wird dem Änderungsdatum. Der entsprechende TAG heisst &#039;DateModify&#039;. Der gesuchte Wert soll nach dem 23.03.2021 08:05:14 liegen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Metadatum Datum.png]]&lt;br /&gt;
&lt;br /&gt;
==Dateien auch in den Unterordnern prüfen==&lt;br /&gt;
&lt;br /&gt;
Soll auch in Unterordner geprüft werden, ist folgende Checkbox zu aktivieren:&lt;br /&gt;
&lt;br /&gt;
[[File:filetest_rekursiv.png]]&lt;br /&gt;
&lt;br /&gt;
Der Filetest beim Abschliessen eines clientseitigen Arbeitsschrittes ist nicht rekursiv.&lt;br /&gt;
&lt;br /&gt;
== Dateinamen auf Regex überprüfen ==&lt;br /&gt;
Sie können den Dateinamen mithilfe eines Regex überprüfen lassen.&lt;br /&gt;
Wählen Sie dazu die Kondition &amp;quot;Dateiname&amp;quot; und den Operator &amp;quot;entspricht Regex&amp;quot;, dann &#039;&#039;&#039;muss jedes File&#039;&#039;&#039; im Objektordner dem Regex entsprechen.&lt;br /&gt;
Wenn Sie &amp;quot;entspricht nicht Regex&amp;quot; wählen, dann &#039;&#039;&#039;darf kein File&#039;&#039;&#039; dem Regex entsprechen.&lt;br /&gt;
&lt;br /&gt;
Tool um Regex zu schreiben: https://regex101.com&lt;br /&gt;
&lt;br /&gt;
[[Datei:Filetest regexmatching.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Barcodes finden==&lt;br /&gt;
&lt;br /&gt;
Ermittelt, ob die Seiten einen Barcode besitzen. Ein bestimmer Suchwert für den Inhalt des Barcodes kann ebenfalls als Einschränkung mitgegeben werden.&lt;br /&gt;
&lt;br /&gt;
Kann alle Seiten, oder nur die geraden, oder nur die ungeraden prüfen. Wenn wir hier von Seiten sprechen, dann sind damit einzelne Dateien gemeint, welche in der Regel eine einzelne Seite darstellen. Die Reihenfolge der nach Namen sortierten Dateien im Dateisystem legt dabei die Seitenzahl fest. Die erste Datei - Sortiernummer 1 - entspricht demnach einer ungeraden Seite. Datei achte Datei - Sortiernummer 8 - einer geraden Seite.&lt;br /&gt;
&lt;br /&gt;
Unterstüzte Dateitypen - alle gängigen Bildformate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Attribut:&#039;&#039;&#039; SeiteHatBarcodes&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Operator Code:&#039;&#039;&#039;  ( = )&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wert:&#039;&#039;&#039; A/U/G/[Zahl]&#039;&#039;&#039;,&#039;&#039;&#039;Barcodeinhalt,Barcodetyp&lt;br /&gt;
&lt;br /&gt;
A = alle Seiten, U = ungerade Seiten, G = gerade Seiten, [Zahl] = zB. 5 =&amp;gt; Hat es auf der 5. Seite einen Barcode?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bsp.:&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
1) Suche auf ungeraden Seiten nach einem Barcode: &#039;&#039;&#039;Wert = 1&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
2) Suche auf geraden Seiten (2) nach einem Barcode mit dem Wert 0783A-123: &#039;&#039;&#039;Wert = 2,0783A-123&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Merke:&#039;&#039;&#039; Die Suche nach einem Wert funktioniert aktuell nur für den ersten gefundenen Barcode! Wenn es mehrere Barcodes auf der Seite gibt, wird jeweils der erste Ausgewertet.&lt;br /&gt;
&lt;br /&gt;
Falls eine Zahl angegeben wird, kann der Barcodetyp definiert werden. In der anderen Fällen ist der Parameter nicht implementiert. Ebenfalls kann der Wert ein Regex sein, sofern eine Zahl definiert ist.&lt;br /&gt;
&lt;br /&gt;
==Essentielle Felder==&lt;br /&gt;
  AR_FILETEST, HZ_FILETEST   &#039;&#039;Code kTab Attribut kTab Operator kTab Wert(e) kCR&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  HZ_TESTERGEBNIS&lt;br /&gt;
&lt;br /&gt;
  HZ_FILEVERHALTEN&lt;br /&gt;
&lt;br /&gt;
==Pane im Produktionsauftrag (FHK_Maske)==&lt;br /&gt;
&lt;br /&gt;
[[File:0.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=CheckIn&amp;diff=9175</id>
		<title>CheckIn</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=CheckIn&amp;diff=9175"/>
		<updated>2025-03-05T14:15:45Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3487: Text um Bruder erstellen erweitert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  1809&lt;br /&gt;
;Systemtyp: &lt;br /&gt;
  13&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
&lt;br /&gt;
Arbeitsschritt der Wareneingangskontrolle.&lt;br /&gt;
&lt;br /&gt;
Arbeitnehmer checkt die Objekte (z.B Boxen) hier in den Workflow ein und erfasst ggf. defekte an den Objekten.&lt;br /&gt;
&lt;br /&gt;
An diesem Schritt können grundsätzlich keine Objekte erstellt werden. Die Objekte müssen zuerst erstellt worden sein und erscheinen dann in der Auswahlliste.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es besteht die Möglichkeit, das duplizieren von Objekten zu erlauben (HZ Konfiguration), so dass bei unerwartetem Wareneingang oder bei Fehlern in der Vorerfassung, ein am Eingang tatsächlich vorhandenes Objekt gleich in den Workflow eingegliedert werden kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es besteht die Möglichkeit, neue Brüder im CheckIn Fenster zu erstellen. Dazu klicken Sie die Checkbox &amp;quot;Neue Objekte erstellen erlaub&amp;quot; an und wählen einen Objekttyp für diese neuen Objekte aus. Es wird ein neuer Button im Fenster sichtbar der auf der selben Ebene wie das ausgewählte Objekt ein neues anlegt. Die Signatur muss vom Benutzter eingegeben werden.&lt;br /&gt;
&lt;br /&gt;
*Metadaten werden nicht dupliziert! Diese müssen von Hand eingegeben werden. Die Bearbeitung von Metadaten muss ebenfalls zuerst über eine Konfiguration ermöglicht werden.&lt;br /&gt;
*Tranchen, bzw. Objekte auf der ersten Ebene können nicht dupliziert werden.&lt;br /&gt;
*Die Signatur wird 1-1 übernommen. Wird der Schalter duplizieren jedoch mit gedrückter SHIFT Taste aufgerufen, dann kann der Signatur ein zusätzlicher Text nach freier Eingabe angehängt werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Über den Schalter &#039;Fehlend markieren&#039; kann ein Objekt als nicht geliefert / vorhanden markiert werden. Das Objekt wird dabei zum zweiten Ausgang verschoben und der Status auf &#039;fehlt&#039; gesetzt. Das Objekt kann nun nicht mehr eingechekct werden! &amp;lt;br&amp;gt; &#039;&#039;&#039;Ein erneutes drücken des Schalters setzt die Markierung wieder zurück&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Status:&lt;br /&gt;
&lt;br /&gt;
 &#039;neu&#039;                   Objekte welche eingecheckt werden müssen&lt;br /&gt;
 &#039;früher eingecheckt&#039;    Objekte welche bereits eingecheckt wurden.&lt;br /&gt;
 &#039;fehlt&#039;                 Objekte welche nicht vorhanden sind oder nicht geliefert werden.&lt;br /&gt;
&lt;br /&gt;
==Ausgänge==&lt;br /&gt;
&lt;br /&gt;
Der Schritt besitzt zwei Ausgänge.&lt;br /&gt;
&lt;br /&gt;
 Eingecheckt - Normalfall nach erfolgtem einbuchen&lt;br /&gt;
 Objekt fehlt - Objekt wurde als fehlend markiert&lt;br /&gt;
&lt;br /&gt;
==Maske FDO_CheckIn==&lt;br /&gt;
&lt;br /&gt;
[[Datei:FDO CheckIn.png | 800px]]&lt;br /&gt;
&lt;br /&gt;
==Essentielle Felder==&lt;br /&gt;
  Felder zur Datenbankverbindung wie im Systemtyp 8 SFTP-Upload.&lt;br /&gt;
&lt;br /&gt;
  HZ_BEZEICHNUNG          &#039;&#039;URL für Postgres DB&#039;&#039;&lt;br /&gt;
  HZ_USERNAME             &#039;&#039;Benutzername&amp;quot;&lt;br /&gt;
  HZ_PASSWORD             &#039;&#039;Password&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  HZ_HASHTYP              &#039;&#039;Duplizieren erlauben&#039;&#039;&lt;br /&gt;
  HZ_KINDERVERDOPPELN     &#039;&#039;Bruder erstellen erlauben&#039;&#039;&lt;br /&gt;
  HZ_DY_SEQ1              &#039;&#039;Welcher Objekttyp hat der neue Bruder&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Pane im Produktionsauftrag (FHK_Maske)==&lt;br /&gt;
&lt;br /&gt;
[[Datei:FHZ STyp013.png | 400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=CheckIn&amp;diff=9174</id>
		<title>CheckIn</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=CheckIn&amp;diff=9174"/>
		<updated>2025-03-05T14:13:37Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3487: Maske aktualisiert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  1809&lt;br /&gt;
;Systemtyp: &lt;br /&gt;
  13&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
&lt;br /&gt;
Arbeitsschritt der Wareneingangskontrolle.&lt;br /&gt;
&lt;br /&gt;
Arbeitnehmer checkt die Objekte (z.B Boxen) hier in den Workflow ein und erfasst ggf. defekte an den Objekten.&lt;br /&gt;
&lt;br /&gt;
An diesem Schritt können grundsätzlich keine Objekte erstellt werden. Die Objekte müssen zuerst erstellt worden sein und erscheinen dann in der Auswahlliste.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es besteht die Möglichkeit, das duplizieren von Objekten zu erlauben (HZ Konfiguration), so dass bei unerwartetem Wareneingang oder bei Fehlern in der Vorerfassung, ein am Eingang tatsächlich vorhandenes Objekt gleich in den Workflow eingegliedert werden kann.&lt;br /&gt;
&lt;br /&gt;
*Metadaten werden nicht dupliziert! Diese müssen von Hand eingegeben werden. Die Bearbeitung von Metadaten muss ebenfalls zuerst über eine Konfiguration ermöglicht werden.&lt;br /&gt;
*Tranchen, bzw. Objekte auf der ersten Ebene können nicht dupliziert werden.&lt;br /&gt;
*Die Signatur wird 1-1 übernommen. Wird der Schalter duplizieren jedoch mit gedrückter SHIFT Taste aufgerufen, dann kann der Signatur ein zusätzlicher Text nach freier Eingabe angehängt werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Über den Schalter &#039;Fehlend markieren&#039; kann ein Objekt als nicht geliefert / vorhanden markiert werden. Das Objekt wird dabei zum zweiten Ausgang verschoben und der Status auf &#039;fehlt&#039; gesetzt. Das Objekt kann nun nicht mehr eingechekct werden! &amp;lt;br&amp;gt; &#039;&#039;&#039;Ein erneutes drücken des Schalters setzt die Markierung wieder zurück&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Status:&lt;br /&gt;
&lt;br /&gt;
 &#039;neu&#039;                   Objekte welche eingecheckt werden müssen&lt;br /&gt;
 &#039;früher eingecheckt&#039;    Objekte welche bereits eingecheckt wurden.&lt;br /&gt;
 &#039;fehlt&#039;                 Objekte welche nicht vorhanden sind oder nicht geliefert werden.&lt;br /&gt;
&lt;br /&gt;
==Ausgänge==&lt;br /&gt;
&lt;br /&gt;
Der Schritt besitzt zwei Ausgänge.&lt;br /&gt;
&lt;br /&gt;
 Eingecheckt - Normalfall nach erfolgtem einbuchen&lt;br /&gt;
 Objekt fehlt - Objekt wurde als fehlend markiert&lt;br /&gt;
&lt;br /&gt;
==Maske FDO_CheckIn==&lt;br /&gt;
&lt;br /&gt;
[[Datei:FDO CheckIn.png | 800px]]&lt;br /&gt;
&lt;br /&gt;
==Essentielle Felder==&lt;br /&gt;
  Felder zur Datenbankverbindung wie im Systemtyp 8 SFTP-Upload.&lt;br /&gt;
&lt;br /&gt;
  HZ_BEZEICHNUNG          &#039;&#039;URL für Postgres DB&#039;&#039;&lt;br /&gt;
  HZ_USERNAME             &#039;&#039;Benutzername&amp;quot;&lt;br /&gt;
  HZ_PASSWORD             &#039;&#039;Password&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  HZ_HASHTYP              &#039;&#039;Duplizieren erlauben&#039;&#039;&lt;br /&gt;
  HZ_KINDERVERDOPPELN     &#039;&#039;Bruder erstellen erlauben&#039;&#039;&lt;br /&gt;
  HZ_DY_SEQ1              &#039;&#039;Welcher Objekttyp hat der neue Bruder&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Pane im Produktionsauftrag (FHK_Maske)==&lt;br /&gt;
&lt;br /&gt;
[[Datei:FHZ STyp013.png | 400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Datei:FDO_CheckIn.png&amp;diff=9173</id>
		<title>Datei:FDO CheckIn.png</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Datei:FDO_CheckIn.png&amp;diff=9173"/>
		<updated>2025-03-05T14:13:12Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;CheckIn Fenster&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=CheckIn&amp;diff=9172</id>
		<title>CheckIn</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=CheckIn&amp;diff=9172"/>
		<updated>2025-03-05T14:11:37Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3487: Essentielle Felder aktualisiert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  1809&lt;br /&gt;
;Systemtyp: &lt;br /&gt;
  13&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
&lt;br /&gt;
Arbeitsschritt der Wareneingangskontrolle.&lt;br /&gt;
&lt;br /&gt;
Arbeitnehmer checkt die Objekte (z.B Boxen) hier in den Workflow ein und erfasst ggf. defekte an den Objekten.&lt;br /&gt;
&lt;br /&gt;
An diesem Schritt können grundsätzlich keine Objekte erstellt werden. Die Objekte müssen zuerst erstellt worden sein und erscheinen dann in der Auswahlliste.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es besteht die Möglichkeit, das duplizieren von Objekten zu erlauben (HZ Konfiguration), so dass bei unerwartetem Wareneingang oder bei Fehlern in der Vorerfassung, ein am Eingang tatsächlich vorhandenes Objekt gleich in den Workflow eingegliedert werden kann.&lt;br /&gt;
&lt;br /&gt;
*Metadaten werden nicht dupliziert! Diese müssen von Hand eingegeben werden. Die Bearbeitung von Metadaten muss ebenfalls zuerst über eine Konfiguration ermöglicht werden.&lt;br /&gt;
*Tranchen, bzw. Objekte auf der ersten Ebene können nicht dupliziert werden.&lt;br /&gt;
*Die Signatur wird 1-1 übernommen. Wird der Schalter duplizieren jedoch mit gedrückter SHIFT Taste aufgerufen, dann kann der Signatur ein zusätzlicher Text nach freier Eingabe angehängt werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Über den Schalter &#039;Fehlend markieren&#039; kann ein Objekt als nicht geliefert / vorhanden markiert werden. Das Objekt wird dabei zum zweiten Ausgang verschoben und der Status auf &#039;fehlt&#039; gesetzt. Das Objekt kann nun nicht mehr eingechekct werden! &amp;lt;br&amp;gt; &#039;&#039;&#039;Ein erneutes drücken des Schalters setzt die Markierung wieder zurück&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Status:&lt;br /&gt;
&lt;br /&gt;
 &#039;neu&#039;                   Objekte welche eingecheckt werden müssen&lt;br /&gt;
 &#039;früher eingecheckt&#039;    Objekte welche bereits eingecheckt wurden.&lt;br /&gt;
 &#039;fehlt&#039;                 Objekte welche nicht vorhanden sind oder nicht geliefert werden.&lt;br /&gt;
&lt;br /&gt;
==Ausgänge==&lt;br /&gt;
&lt;br /&gt;
Der Schritt besitzt zwei Ausgänge.&lt;br /&gt;
&lt;br /&gt;
 Eingecheckt - Normalfall nach erfolgtem einbuchen&lt;br /&gt;
 Objekt fehlt - Objekt wurde als fehlend markiert&lt;br /&gt;
&lt;br /&gt;
==Maske FDO_CheckIn==&lt;br /&gt;
&lt;br /&gt;
[[File:FDO_Checkin.png]]&lt;br /&gt;
&lt;br /&gt;
==Essentielle Felder==&lt;br /&gt;
  Felder zur Datenbankverbindung wie im Systemtyp 8 SFTP-Upload.&lt;br /&gt;
&lt;br /&gt;
  HZ_BEZEICHNUNG          &#039;&#039;URL für Postgres DB&#039;&#039;&lt;br /&gt;
  HZ_USERNAME             &#039;&#039;Benutzername&amp;quot;&lt;br /&gt;
  HZ_PASSWORD             &#039;&#039;Password&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  HZ_HASHTYP              &#039;&#039;Duplizieren erlauben&#039;&#039;&lt;br /&gt;
  HZ_KINDERVERDOPPELN     &#039;&#039;Bruder erstellen erlauben&#039;&#039;&lt;br /&gt;
  HZ_DY_SEQ1              &#039;&#039;Welcher Objekttyp hat der neue Bruder&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Pane im Produktionsauftrag (FHK_Maske)==&lt;br /&gt;
&lt;br /&gt;
[[Datei:FHZ STyp013.png | 400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=CheckIn&amp;diff=9171</id>
		<title>CheckIn</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=CheckIn&amp;diff=9171"/>
		<updated>2025-03-05T14:10:10Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3487: Wiki aktualisiert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  1809&lt;br /&gt;
;Systemtyp: &lt;br /&gt;
  13&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
&lt;br /&gt;
Arbeitsschritt der Wareneingangskontrolle.&lt;br /&gt;
&lt;br /&gt;
Arbeitnehmer checkt die Objekte (z.B Boxen) hier in den Workflow ein und erfasst ggf. defekte an den Objekten.&lt;br /&gt;
&lt;br /&gt;
An diesem Schritt können grundsätzlich keine Objekte erstellt werden. Die Objekte müssen zuerst erstellt worden sein und erscheinen dann in der Auswahlliste.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es besteht die Möglichkeit, das duplizieren von Objekten zu erlauben (HZ Konfiguration), so dass bei unerwartetem Wareneingang oder bei Fehlern in der Vorerfassung, ein am Eingang tatsächlich vorhandenes Objekt gleich in den Workflow eingegliedert werden kann.&lt;br /&gt;
&lt;br /&gt;
*Metadaten werden nicht dupliziert! Diese müssen von Hand eingegeben werden. Die Bearbeitung von Metadaten muss ebenfalls zuerst über eine Konfiguration ermöglicht werden.&lt;br /&gt;
*Tranchen, bzw. Objekte auf der ersten Ebene können nicht dupliziert werden.&lt;br /&gt;
*Die Signatur wird 1-1 übernommen. Wird der Schalter duplizieren jedoch mit gedrückter SHIFT Taste aufgerufen, dann kann der Signatur ein zusätzlicher Text nach freier Eingabe angehängt werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Über den Schalter &#039;Fehlend markieren&#039; kann ein Objekt als nicht geliefert / vorhanden markiert werden. Das Objekt wird dabei zum zweiten Ausgang verschoben und der Status auf &#039;fehlt&#039; gesetzt. Das Objekt kann nun nicht mehr eingechekct werden! &amp;lt;br&amp;gt; &#039;&#039;&#039;Ein erneutes drücken des Schalters setzt die Markierung wieder zurück&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Status:&lt;br /&gt;
&lt;br /&gt;
 &#039;neu&#039;                   Objekte welche eingecheckt werden müssen&lt;br /&gt;
 &#039;früher eingecheckt&#039;    Objekte welche bereits eingecheckt wurden.&lt;br /&gt;
 &#039;fehlt&#039;                 Objekte welche nicht vorhanden sind oder nicht geliefert werden.&lt;br /&gt;
&lt;br /&gt;
==Ausgänge==&lt;br /&gt;
&lt;br /&gt;
Der Schritt besitzt zwei Ausgänge.&lt;br /&gt;
&lt;br /&gt;
 Eingecheckt - Normalfall nach erfolgtem einbuchen&lt;br /&gt;
 Objekt fehlt - Objekt wurde als fehlend markiert&lt;br /&gt;
&lt;br /&gt;
==Maske FDO_CheckIn==&lt;br /&gt;
&lt;br /&gt;
[[File:FDO_Checkin.png]]&lt;br /&gt;
&lt;br /&gt;
==Essentielle Felder==&lt;br /&gt;
  Felder zur Datenbankverbindung wie im Systemtyp 8 SFTP-Upload.&lt;br /&gt;
&lt;br /&gt;
  HZ_BEZEICHNUNG   &#039;&#039;URL für Postgres DB&#039;&#039;&lt;br /&gt;
  HZ_USERNAME      &#039;&#039;Benutzername&amp;quot;&lt;br /&gt;
  HZ_PASSWORD      &#039;&#039;Password&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  HZ_HASHTYP       &#039;&#039;Duplizieren erlauben&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Pane im Produktionsauftrag (FHK_Maske)==&lt;br /&gt;
&lt;br /&gt;
[[Datei:FHZ STyp013.png | 400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Datei:FHZ_STyp013.png&amp;diff=9170</id>
		<title>Datei:FHZ STyp013.png</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Datei:FHZ_STyp013.png&amp;diff=9170"/>
		<updated>2025-03-05T14:09:28Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Konfiguration CheckIn&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Objekthierarchie_%C3%A4ndern&amp;diff=9169</id>
		<title>Objekthierarchie ändern</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Objekthierarchie_%C3%A4ndern&amp;diff=9169"/>
		<updated>2025-03-05T14:02:43Z</updated>

		<summary type="html">&lt;p&gt;Silvan: /* Konfigurationsfenster im Produktionsauftrag */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  2237, 3371&lt;br /&gt;
;Systemtyp: &lt;br /&gt;
  44&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
&lt;br /&gt;
Weist einem Objekt einen neuen Ahnen zu. Der neue Ahne muss dazu zwingend ein Geschwister des Objektes sein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Es gibt dafür vier Varianten:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;1. Älteres Geschwister, welches von einem anderen Objekt-Typ sein muss, finden.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für diesen Fall gibt es nur einen Ausgang.&lt;br /&gt;
&lt;br /&gt;
Unter den älteren Geschwistern der DOs wird das nächst älteste gesucht, das einen anderen Typ (DO_DY_SEQ) hat. Also das mit der grössten DO_SEQ davon. &lt;br /&gt;
&lt;br /&gt;
Es werden folglich nur Objekte berücksichtigt, welche bereits vor dem aktuellen Objekt entstanden sind (eine kleine DO_SEQ besitzen, als das Objekt selbst).&lt;br /&gt;
&lt;br /&gt;
Wenn es dieses gibt, dann soll das aktuelle DO zu einem Kind des gefundenen DOs werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Falls es kein Geschwister gibt bleibt alles wie es ist. Das DO geht auf jeden Fall zum nächsten Schritt.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;2. Geschwister über dessen DOSignatur finden. Die Name für die zu suchenden DOSignatur wird aus einem Metadatum des Objektes geholt.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dieser Fall besitzt zwei Ausgänge.&lt;br /&gt;
&lt;br /&gt;
Es muss ein Metadatum angegeben werden, in welchem die zu suchende DOSignatur hinterlegt wurde.&lt;br /&gt;
&lt;br /&gt;
Es muss hier genau ein Geschwister vorhanden sein, sonst geht das Objekt zum zweiten Ausgang&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nur wenn ein Geschwister gefunden wurde, geht das DO zum nächsten Schritt. Wird kein geschwister gefunden geht das Obhjekt zum Ausgang 2.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
E.g.: Kein Geschwister mit gesuchter DOSignatur -&amp;gt; DO Fehler. Zwei Geschwister mit gesuchter DOSignatur -&amp;gt; DO Fehler.&lt;br /&gt;
&lt;br /&gt;
Merke: Der DO Typ ist hier nicht relevant. Genausowenig wie die Enstehungsfolge (logisches Alter) der Objekte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;3. Objekt wird zum Kind seines Grossvaters&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In diesem Fall wird das Kind um eine Ebene nach oben geschoben. Das heisst es wird zum Kind seines Grossvaters oder zum Bruder seines Vaters.&lt;br /&gt;
&lt;br /&gt;
Gibt es kein Grossvater, so landet das Objekt einfach auf der obersten Ebene.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;4. Objekt wird zum Kind eines bestimmen Objektes&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In diesem Fall wird das Objekt zu einem Kind eines spezifisch definierten Vaters. Dazu geben Sie eine Objektnummer im Konfigurationsfenster an. 0 ist auch ein gültiger Wert; Dadurch landet das Objekt auf der obersten Ebene der Projekthierarchie.&lt;br /&gt;
&lt;br /&gt;
Sollte es den konfigurierten, neuen Vater nicht geben, stoppt der Arbeitsschritt mit einem Fehler.&lt;br /&gt;
&lt;br /&gt;
==Essentielle Felder==&lt;br /&gt;
  HZ_FILEVERHALTEN - Die auszuführende Variante (Checkbox Auswahl 0/1)&lt;br /&gt;
  HZ_FILENAME - Das Metadatum welches die gesuchte DOSignatur hält&lt;br /&gt;
  HZ_BARCODEFILEWEG - Objektnummer des neuen Vaters&lt;br /&gt;
&lt;br /&gt;
==Konfigurationsfenster im Produktionsauftrag==&lt;br /&gt;
&lt;br /&gt;
Fall 1: Nur ein Ausgang&lt;br /&gt;
&lt;br /&gt;
[[Datei:FHZ STyp044.png | 500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fall 2: Zwei Ausgänge&lt;br /&gt;
&lt;br /&gt;
[[Datei:FHZ STyp044 2.png | 500px]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Datei:FHZ_STyp044_2.png&amp;diff=9168</id>
		<title>Datei:FHZ STyp044 2.png</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Datei:FHZ_STyp044_2.png&amp;diff=9168"/>
		<updated>2025-03-05T14:02:21Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Konfiguration für HZ 44&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Datei:FHZ_STyp044.png&amp;diff=9167</id>
		<title>Datei:FHZ STyp044.png</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Datei:FHZ_STyp044.png&amp;diff=9167"/>
		<updated>2025-03-05T14:00:55Z</updated>

		<summary type="html">&lt;p&gt;Silvan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Konfigurationsfenster für HZ 44&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Objekthierarchie_%C3%A4ndern&amp;diff=9166</id>
		<title>Objekthierarchie ändern</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Objekthierarchie_%C3%A4ndern&amp;diff=9166"/>
		<updated>2025-03-05T13:58:37Z</updated>

		<summary type="html">&lt;p&gt;Silvan: /* Beschreibung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  2237, 3371&lt;br /&gt;
;Systemtyp: &lt;br /&gt;
  44&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
&lt;br /&gt;
Weist einem Objekt einen neuen Ahnen zu. Der neue Ahne muss dazu zwingend ein Geschwister des Objektes sein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Es gibt dafür vier Varianten:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;1. Älteres Geschwister, welches von einem anderen Objekt-Typ sein muss, finden.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für diesen Fall gibt es nur einen Ausgang.&lt;br /&gt;
&lt;br /&gt;
Unter den älteren Geschwistern der DOs wird das nächst älteste gesucht, das einen anderen Typ (DO_DY_SEQ) hat. Also das mit der grössten DO_SEQ davon. &lt;br /&gt;
&lt;br /&gt;
Es werden folglich nur Objekte berücksichtigt, welche bereits vor dem aktuellen Objekt entstanden sind (eine kleine DO_SEQ besitzen, als das Objekt selbst).&lt;br /&gt;
&lt;br /&gt;
Wenn es dieses gibt, dann soll das aktuelle DO zu einem Kind des gefundenen DOs werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Falls es kein Geschwister gibt bleibt alles wie es ist. Das DO geht auf jeden Fall zum nächsten Schritt.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;2. Geschwister über dessen DOSignatur finden. Die Name für die zu suchenden DOSignatur wird aus einem Metadatum des Objektes geholt.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dieser Fall besitzt zwei Ausgänge.&lt;br /&gt;
&lt;br /&gt;
Es muss ein Metadatum angegeben werden, in welchem die zu suchende DOSignatur hinterlegt wurde.&lt;br /&gt;
&lt;br /&gt;
Es muss hier genau ein Geschwister vorhanden sein, sonst geht das Objekt zum zweiten Ausgang&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nur wenn ein Geschwister gefunden wurde, geht das DO zum nächsten Schritt. Wird kein geschwister gefunden geht das Obhjekt zum Ausgang 2.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
E.g.: Kein Geschwister mit gesuchter DOSignatur -&amp;gt; DO Fehler. Zwei Geschwister mit gesuchter DOSignatur -&amp;gt; DO Fehler.&lt;br /&gt;
&lt;br /&gt;
Merke: Der DO Typ ist hier nicht relevant. Genausowenig wie die Enstehungsfolge (logisches Alter) der Objekte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;3. Objekt wird zum Kind seines Grossvaters&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In diesem Fall wird das Kind um eine Ebene nach oben geschoben. Das heisst es wird zum Kind seines Grossvaters oder zum Bruder seines Vaters.&lt;br /&gt;
&lt;br /&gt;
Gibt es kein Grossvater, so landet das Objekt einfach auf der obersten Ebene.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;4. Objekt wird zum Kind eines bestimmen Objektes&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In diesem Fall wird das Objekt zu einem Kind eines spezifisch definierten Vaters. Dazu geben Sie eine Objektnummer im Konfigurationsfenster an. 0 ist auch ein gültiger Wert; Dadurch landet das Objekt auf der obersten Ebene der Projekthierarchie.&lt;br /&gt;
&lt;br /&gt;
Sollte es den konfigurierten, neuen Vater nicht geben, stoppt der Arbeitsschritt mit einem Fehler.&lt;br /&gt;
&lt;br /&gt;
==Essentielle Felder==&lt;br /&gt;
  HZ_FILEVERHALTEN - Die auszuführende Variante (Checkbox Auswahl 0/1)&lt;br /&gt;
  HZ_FILENAME - Das Metadatum welches die gesuchte DOSignatur hält&lt;br /&gt;
  HZ_BARCODEFILEWEG - Objektnummer des neuen Vaters&lt;br /&gt;
&lt;br /&gt;
==Konfigurationsfenster im Produktionsauftrag==&lt;br /&gt;
&lt;br /&gt;
Fall 1: Nur ein Ausgang&lt;br /&gt;
&lt;br /&gt;
[[File:Objekthierarchie1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fall 2: Zwei Ausgänge&lt;br /&gt;
&lt;br /&gt;
[[File:Objekthierarchie.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Objekthierarchie_%C3%A4ndern&amp;diff=9165</id>
		<title>Objekthierarchie ändern</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Objekthierarchie_%C3%A4ndern&amp;diff=9165"/>
		<updated>2025-03-05T13:53:46Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3488: Wiki aktualisiert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Mantiseinträge: &lt;br /&gt;
  2237, 3371&lt;br /&gt;
;Systemtyp: &lt;br /&gt;
  44&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
&lt;br /&gt;
Weist einem Objekt einen neuen Ahnen zu. Der neue Ahne muss dazu zwingend ein Geschwister des Objektes sein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Es gibt dafür zwei Varianten:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;1. Älteres Geschwister, welches von einem anderen Objekt-Typ sein muss, finden.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für diesen Fall gibt es nur einen Ausgang.&lt;br /&gt;
&lt;br /&gt;
Unter den älteren Geschwistern der DOs wird das nächst älteste gesucht, das einen anderen Typ (DO_DY_SEQ) hat. Also das mit der grössten DO_SEQ davon. &lt;br /&gt;
&lt;br /&gt;
Es werden folglich nur Objekte berücksichtigt, welche bereits vor dem aktuellen Objekt entstanden sind (eine kleine DO_SEQ besitzen, als das Objekt selbst).&lt;br /&gt;
&lt;br /&gt;
Wenn es dieses gibt, dann soll das aktuelle DO zu einem Kind des gefundenen DOs werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Falls es kein Geschwister gibt bleibt alles wie es ist. Das DO geht auf jeden Fall zum nächsten Schritt.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;2. Geschwister über dessen DOSignatur finden. Die Name für die zu suchenden DOSignatur wird aus einem Metadatum des Objektes geholt.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dieser Fall besitzt zwei Ausgänge.&lt;br /&gt;
&lt;br /&gt;
Es muss ein Metadatum angegeben werden, in welchem die zu suchende DOSignatur hinterlegt wurde.&lt;br /&gt;
&lt;br /&gt;
Es muss hier genau ein Geschwister vorhanden sein, sonst geht das Objekt zum zweiten Ausgang&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nur wenn ein Geschwister gefunden wurde, geht das DO zum nächsten Schritt. Wird kein geschwister gefunden geht das Obhjekt zum Ausgang 2.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
E.g.: Kein Geschwister mit gesuchter DOSignatur -&amp;gt; DO Fehler. Zwei Geschwister mit gesuchter DOSignatur -&amp;gt; DO Fehler.&lt;br /&gt;
&lt;br /&gt;
Merke: Der DO Typ ist hier nicht relevant. Genausowenig wie die Enstehungsfolge (logisches Alter) der Objekte.&lt;br /&gt;
&lt;br /&gt;
==Essentielle Felder==&lt;br /&gt;
  HZ_FILEVERHALTEN - Die auszuführende Variante (Checkbox Auswahl 0/1)&lt;br /&gt;
  HZ_FILENAME - Das Metadatum welches die gesuchte DOSignatur hält&lt;br /&gt;
  HZ_BARCODEFILEWEG - Objektnummer des neuen Vaters&lt;br /&gt;
&lt;br /&gt;
==Konfigurationsfenster im Produktionsauftrag==&lt;br /&gt;
&lt;br /&gt;
Fall 1: Nur ein Ausgang&lt;br /&gt;
&lt;br /&gt;
[[File:Objekthierarchie1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fall 2: Zwei Ausgänge&lt;br /&gt;
&lt;br /&gt;
[[File:Objekthierarchie.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Workflowschritt]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Effizienzfaktor_Angestellte&amp;diff=9150</id>
		<title>Effizienzfaktor Angestellte</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Effizienzfaktor_Angestellte&amp;diff=9150"/>
		<updated>2025-02-18T08:41:39Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3113&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Fensternamen ===&lt;br /&gt;
  FAN_Einstell&lt;br /&gt;
  FAN_Maske1&lt;br /&gt;
  FAN_ACLSQuotientSpot&lt;br /&gt;
  FAN_ACLSUbersicht&lt;br /&gt;
&lt;br /&gt;
== Effizienzfaktor ==&lt;br /&gt;
Um Vorhersagen über das Fertigstellungsdatum eines Arbeitsschrittes machen zu können, ist es wichtig zu wissen wie viel Arbeit die einzelnen Angestellten an einem bestimmten Tag verrichten. Der Effizienzfaktor soll den Unterschied zwischen den erfassten Leistungen (LS) und den angegebenen Arbeitszeiten im BSB definieren. Ein Effizienzfaktor von 60 % bedeutet, dass 60 % der Zeit welcher der Angestellte im BSB verbringt auch im Helper als Leistung erfasst ist. Das bedeutet wenn der Angestellte XY 8 Stunden im BSB stempelt rechnen wir mit nur 60 % (also 4.8 h) in welchen er wirklich an Objekten arbeitet.&lt;br /&gt;
&lt;br /&gt;
== Globaler Effizienzfaktor ==&lt;br /&gt;
===Ort===&lt;br /&gt;
  Einstellungen -&amp;gt; Personal -&amp;gt; Standardwert für das Verhältnis von Helper Leistungen...&lt;br /&gt;
&lt;br /&gt;
===Beschreibung===&lt;br /&gt;
Hier kann ein Globaler Effizienzfaktor (in Prozent) konfiguriert werden. Dieser wird von allen Angestellten verwendet, welche keinen eigenen Effizienzfaktor besitzen.&amp;lt;br&amp;gt;&lt;br /&gt;
Beispiel: 75.00 % = 75 % aller Arbeitszeit im BSB ist auch im Helper als Leistung erfasst.&lt;br /&gt;
&lt;br /&gt;
[[Datei:FAN Einstell.png|900px]]&lt;br /&gt;
&lt;br /&gt;
== Effizienzfaktor Angestellter ==&lt;br /&gt;
===Ort===&lt;br /&gt;
  Angestellte -&amp;gt; Menu Angestellte -&amp;gt; Leistung vs. Arbeitszeit Verhältnis&lt;br /&gt;
&lt;br /&gt;
===Beschreibung===&lt;br /&gt;
In diesem Fenster können Sie für jeden Angestellten einen eigenen Effizienzfaktor definieren. Mit dem Button &amp;quot;Relevante Angestellte für Produktionsplanung&amp;quot; laden Sie alle Daten der Angestellten, welche die Checkbox &amp;quot;für Termine / Produktion buchbar&amp;quot; markiert haben. Diese Checkbox finden Sie unter Hauptmaske -&amp;gt; Angestellte -&amp;gt; Diverses.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Datei:FAN ACLSQuotientSpot.png|900px]]&lt;br /&gt;
&lt;br /&gt;
1: Wählen Sie welche Daten geladen werden sollen (Kann einen Moment dauern)&amp;lt;br&amp;gt;&lt;br /&gt;
2: Definieren Sie die 2 Zeiträume. Standardmässig ist Zeitraum 1 immer der letzte Monat und Zeitraum 2 die letzten 3 Monate&amp;lt;br&amp;gt;&lt;br /&gt;
3: In dieser Liste sehen Sie alle Angestellte und ihre jeweiligen Effizienzfaktoren in den definierten Zeiträumen. Die letzte Spalte zeigt den aktuellen Faktor oder den Globalen Faktor (Blau).&amp;lt;br&amp;gt;&lt;br /&gt;
4: Klicken Sie auf einen Angestellten und Sie können einen neuen Faktor setzten. Mit dem &amp;quot;Archiv&amp;quot;-Button können Sie einen gesetzten Faktor wieder auf den Globalen zurücksetzten.&amp;lt;br&amp;gt;&lt;br /&gt;
5: Siehe nächsten Abschnitt&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Aufschlüsselung der Effizienzfaktoren ==&lt;br /&gt;
Sie möchten wissen wie der Faktor des Angestellten zustande kommt? Wählen Sie den Angestellten aus und klicken Sie auf den &amp;quot;Info&amp;quot;-Button. In diesem Fenster sehen Sie alle Leistungen sowie alle Arbeitszeiten des Angestellten im ausgewählten Zeitraum.&lt;br /&gt;
&lt;br /&gt;
[[Datei:FAN ACLSUbersicht.png|900px]]&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Produktionsauftrag_Fortschrittsauswertung&amp;diff=9140</id>
		<title>Produktionsauftrag Fortschrittsauswertung</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Produktionsauftrag_Fortschrittsauswertung&amp;diff=9140"/>
		<updated>2025-02-03T13:19:18Z</updated>

		<summary type="html">&lt;p&gt;Silvan: /* Ort */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mithilfe dieses Fensters können Sie sich eine Produktionsauftragsfortschrittsauswertung generieren.&lt;br /&gt;
&lt;br /&gt;
== Ort ==&lt;br /&gt;
&lt;br /&gt;
Um dieses Fenster zu öffnen navigieren sie nach&lt;br /&gt;
  Hauptmaske -&amp;gt; Produktionsaufträge -&amp;gt; Fortschrittsbericht erstellen&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
Es ist wichtig alle Konfiguration abzuschliessen, bevor Sie sich auf die Zahlen der Auswertung verlassen!&lt;br /&gt;
&lt;br /&gt;
=== Produktionsauftrag Stammdaten ===&lt;br /&gt;
&lt;br /&gt;
* Setzten Sie einen Endtermin für den Auftrag&lt;br /&gt;
* Verknüpfen Sie einen Kunden mit dem Auftrag&lt;br /&gt;
* Wählen Sie eine Ansprechperson für den Auftrag&lt;br /&gt;
* Geben Sie die geschätzte Gesamtanzahl der Objekte aller Objekttypen an&lt;br /&gt;
&lt;br /&gt;
=== Aufträge ===&lt;br /&gt;
Verknüpfen Sie alle Aufträge mit dem Produktionsauftrag. Navigieren Sie dazu nach Hauptmaske -&amp;gt; Aufträge -&amp;gt; Kopfdaten und füllen Sie das Feld &amp;quot;Prod. Auftrag&amp;quot; aus. Drücken Sie die &amp;quot;Insert&amp;quot; Taste für ein einfaches Auswählen des Produktionauftrags.&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Produktionsauftrag_Fortschrittsauswertung&amp;diff=9139</id>
		<title>Produktionsauftrag Fortschrittsauswertung</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Produktionsauftrag_Fortschrittsauswertung&amp;diff=9139"/>
		<updated>2025-02-03T13:16:36Z</updated>

		<summary type="html">&lt;p&gt;Silvan: /* Produktionsauftrag Stammdaten */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mithilfe dieses Fensters können Sie sich eine Produktionsauftragsfortschrittsauswertung generieren.&lt;br /&gt;
&lt;br /&gt;
== Ort ==&lt;br /&gt;
&lt;br /&gt;
Um dieses Fenster zu öffnen navigieren sie nach&lt;br /&gt;
  Hauptmaske -&amp;gt; Produktionsaufträge -&amp;gt; Fortschrittsauswertung&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
Es ist wichtig alle Konfiguration abzuschliessen, bevor Sie sich auf die Zahlen der Auswertung verlassen!&lt;br /&gt;
&lt;br /&gt;
=== Produktionsauftrag Stammdaten ===&lt;br /&gt;
&lt;br /&gt;
* Setzten Sie einen Endtermin für den Auftrag&lt;br /&gt;
* Verknüpfen Sie einen Kunden mit dem Auftrag&lt;br /&gt;
* Wählen Sie eine Ansprechperson für den Auftrag&lt;br /&gt;
* Geben Sie die geschätzte Gesamtanzahl der Objekte aller Objekttypen an&lt;br /&gt;
&lt;br /&gt;
=== Aufträge ===&lt;br /&gt;
Verknüpfen Sie alle Aufträge mit dem Produktionsauftrag. Navigieren Sie dazu nach Hauptmaske -&amp;gt; Aufträge -&amp;gt; Kopfdaten und füllen Sie das Feld &amp;quot;Prod. Auftrag&amp;quot; aus. Drücken Sie die &amp;quot;Insert&amp;quot; Taste für ein einfaches Auswählen des Produktionauftrags.&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Produktionsauftrag_Fortschrittsauswertung&amp;diff=9138</id>
		<title>Produktionsauftrag Fortschrittsauswertung</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Produktionsauftrag_Fortschrittsauswertung&amp;diff=9138"/>
		<updated>2025-02-03T12:46:51Z</updated>

		<summary type="html">&lt;p&gt;Silvan: 3113: Neue Wikiseite&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mithilfe dieses Fensters können Sie sich eine Produktionsauftragsfortschrittsauswertung generieren.&lt;br /&gt;
&lt;br /&gt;
== Ort ==&lt;br /&gt;
&lt;br /&gt;
Um dieses Fenster zu öffnen navigieren sie nach&lt;br /&gt;
  Hauptmaske -&amp;gt; Produktionsaufträge -&amp;gt; Fortschrittsauswertung&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
Es ist wichtig alle Konfiguration abzuschliessen, bevor Sie sich auf die Zahlen der Auswertung verlassen!&lt;br /&gt;
&lt;br /&gt;
=== Produktionsauftrag Stammdaten ===&lt;br /&gt;
&lt;br /&gt;
* Setzten Sie einen Endtermin für den Auftrag&lt;br /&gt;
* Verknüpfen Sie einen Kunden mit dem Auftrag&lt;br /&gt;
* Wählen Sie eine Ansprechperson für den Auftrag&lt;br /&gt;
&lt;br /&gt;
=== Aufträge ===&lt;br /&gt;
Verknüpfen Sie alle Aufträge mit dem Produktionsauftrag. Navigieren Sie dazu nach Hauptmaske -&amp;gt; Aufträge -&amp;gt; Kopfdaten und füllen Sie das Feld &amp;quot;Prod. Auftrag&amp;quot; aus. Drücken Sie die &amp;quot;Insert&amp;quot; Taste für ein einfaches Auswählen des Produktionauftrags.&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
	<entry>
		<id>https://helper.ch/wiki/index.php?title=Cockpit&amp;diff=9137</id>
		<title>Cockpit</title>
		<link rel="alternate" type="text/html" href="https://helper.ch/wiki/index.php?title=Cockpit&amp;diff=9137"/>
		<updated>2025-02-03T12:29:28Z</updated>

		<summary type="html">&lt;p&gt;Silvan: /* Daten Anzeigen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Das Cockpit dient zur Planung von Produktionsaufträgen sowie dem Managen von Ressourcen. Es besteht aus mehreren Modulen:&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
* [[Ressourcenzuweisung]]&lt;br /&gt;
* [[Effizienzfaktor Angestellte]]&lt;br /&gt;
* [[Planung von Produktionsaufträgen]]&lt;br /&gt;
&lt;br /&gt;
=== Daten Anzeigen ===&lt;br /&gt;
* [[Planungsübersicht]]&lt;br /&gt;
* [[Produktionsauftrag Fortschrittsauswertung]]&lt;br /&gt;
&lt;br /&gt;
Es ist wichtig in allen oben aufgeführten Modulen jegliche Zahlen zu konfigurieren. Falls Zahlen fehlen, kann es zu falschen Berechnungen kommen!&lt;/div&gt;</summary>
		<author><name>Silvan</name></author>
	</entry>
</feed>