Pulsa ESC para cerrar · Ctrl+K para abrir

AVEVA ArchestrA – Escribir en el Logger desde C#

Clase C# reutilizable que envuelve LoggerDLL.dll para registrar mensajes Info, Warning, Error y Trace directamente en el Logger de AVEVA System Platform e InTouch.

AVEVA ArchestrA – Escribir en el Logger desde C#

Índice

¿Qué es el ArchestrA Log Viewer?

El Log Viewer  es el sistema centralizado de registro de AVEVA System Platform e InTouch. Todos los componentes de la plataforma (Application Server, Historian, InTouch, etc.) vuelcan sus mensajes aquí, se pueden consultar, filtrar y configurar qué queremos registrar, ejemplo de la librería que vamos a crear, por defecto vienen esos tres checkboxes activados.


ArchestrA Log Viewer con los checkboxes de niveles de log activados

Cuando desarrollamos una librería .NET o creamos un nuevo componente .NET que extiende funcionalidades al Application Server / InTouch, lo más limpio es integrarse con este Logger en lugar de escribir en un fichero propio. Para eso vamos a utilizar la propia librería que ya hace esta función en todos sus componentes: LoggerDLL.dll.

Aquí tenemos el ejemplo de los métodos que vamos a utilizar para luego entender mejor nuestra clase en C#:

Métodos exportados de LoggerDLL.dll: REGISTERLOGGERCLIENT, LOGINFO, LOGWARNING, LOGERROR, LOGTRACE

Crear el proyecto Class Library (.NET Framework)

Creamos un proyecto de tipo Class Library (.NET Framework) en Visual Studio. El framework debe ser compatible con la versión de AVEVA instalada (actualmente .NET Framework 4.8).

Voy a mostrar solo el ejemplo de una función dentro de la librería que estamos creando, donde lo más importante es la llamada a la clase que vamos a crear para escribir en el Logger:

Selección del tipo de proyecto y framework

La clase AvevaLogger

El siguiente código es la clase que puedes copiar en tu proyecto, añade una referencia a LoggerDLL.dll (ubicada en C:\Program Files (x86)\Common Files\ArchestrA\LoggerDLL.dll) y ya tienes los cuatro niveles de log disponibles como métodos estáticos.

La clase se auto-inicializa en la primera llamada, registra el cliente con el nombre del ensamblado y se desregistra automáticamente al cerrar el proceso gracias al evento ProcessExit.

csharp
using System;
using System.Reflection;
using System.Runtime.InteropServices;

namespace PHSTraining
{
    internal class AvevaLogger
    {
        private const string LoggerDllPath = @"C:\Program Files (x86)\Common Files\ArchestrA\LoggerDLL.dll";
        private static int _hIdentity = 0;
        private static bool _initialized = false;
        private static string _identityName = string.Empty;

        static AvevaLogger()
        {
            AppDomain.CurrentDomain.ProcessExit += OnProcessExit;
        }

        [DllImport(LoggerDllPath, EntryPoint = "REGISTERLOGGERCLIENT")]
        private static extern int RegisterLoggerClient(ref int hIdentity);

        [DllImport(LoggerDllPath, EntryPoint = "UNREGISTERLOGGERCLIENT")]
        private static extern int UnregisterLoggerClient(ref int hIdentity);

        [DllImport(LoggerDllPath, EntryPoint = "SETIDENTITYNAME", CharSet = CharSet.Unicode)]
        private static extern int SetIdentityName(int hIdentity, string identityName);

        [DllImport(LoggerDllPath, EntryPoint = "LOGINFO", CharSet = CharSet.Unicode)]
        private static extern void LogInfo(int hIdentity, string message);

        [DllImport(LoggerDllPath, EntryPoint = "LOGWARNING", CharSet = CharSet.Unicode)]
        private static extern void LogWarning(int hIdentity, string message);

        [DllImport(LoggerDllPath, EntryPoint = "LOGERROR", CharSet = CharSet.Unicode)]
        private static extern void LogError(int hIdentity, string message);

        [DllImport(LoggerDllPath, EntryPoint = "LOGTRACE", CharSet = CharSet.Unicode)]
        private static extern void LogTrace(int hIdentity, string message);


        public static void LogInfo(string message)
        {
            EnsureInitialized();
            LogInfo(_hIdentity, message ?? string.Empty);
        }

        public static void LogWarning(string message)
        {
            EnsureInitialized();
            LogWarning(_hIdentity, message ?? string.Empty);
        }

        public static void LogError(string message)
        {
            EnsureInitialized();
            LogError(_hIdentity, message ?? string.Empty);
        }

        public static void LogTrace(string message)
        {
            EnsureInitialized();
            LogTrace(_hIdentity, message ?? string.Empty);
        }


        private static void EnsureInitialized()
        {
            if (_initialized) return;

            _identityName = Assembly.GetExecutingAssembly().GetName().Name;

            int rc = RegisterLoggerClient(ref _hIdentity);
            if (rc <= 0 || _hIdentity == 0)
                throw new InvalidOperationException("REGISTERLOGGERCLIENT failed.");

            rc = SetIdentityName(_hIdentity, _identityName);
            if (rc <= 0)
                throw new InvalidOperationException("SETIDENTITYNAME failed.");

            _initialized = true;
        }

        private static void OnProcessExit(object sender, EventArgs e)
        {
            if (_hIdentity != 0)
                UnregisterLoggerClient(ref _hIdentity);

            _hIdentity = 0;
            _initialized = false;
            _identityName = string.Empty;
        }
    }
}

Después de agregar la clase a tu proyecto, ya puedes acabar tu librería / User Control, compilarlo e importarlo a System Platform.

ArchestrA Log Viewer mostrando los mensajes generados por la Script Extension

Una vez importada verás que se ha copiado en:
C:\Program Files (x86)\ArchestrA\Framework\FileRepository\[GalaxyName]\Vendors\ArchestrA

Carpeta Vendors\ArchestrA donde se despliega la Script Extension

Y también podrás comprobar que existe en la siguiente ruta:
C:\Users\Administrator\AppData\Local\Temp\ScriptTemp
donde se generan automáticamente el .aaSLIB y el XML.

Clase AvevaLogger en el editor de Visual Studio
Referencia a LoggerDLL.dll añadida al proyecto

Ahora solo nos falta probarla e implementarla donde corresponda. Este sería el ejemplo:
Un Script que vamos a forzar con el Object Viewer.

Script de prueba forzado desde el Object Viewer

Y la salida en el Log Viewer :-)

Propiedades del proyecto: Output path apuntando a la carpeta temporal de Script Extension

Agradecimientos

Por último y no menos importante: 

«La gratitud en silencio no sirve a nadie.» — Gladys Berthe Stern

Quiero dar las gracias a mi compañero Ivan Comino Martinez.  Estas son las paradojas del destino:

«Cuando trabajaba en Telstar (Syntegon), un gran abrazo para todos los que lo lean, Ivan Comino trabajaba en Systel, y en más de una ocasión me tocó ver código y programas que habían desarrollado y en los comentarios lo primero que leía era "IC" y yo pensaba... ¡Qué bueno, qué buen trabajo! Y ahora tengo la suerte de tenerlo como compañero, aprender con él y trabajar en equipo.» — José Manuel Luque