T5.2: Handles and Logs Runtime Errors

Knowledge Review - InterSystems ObjectScript Specialist

1. Bloques TRY-CATCH

Puntos Clave

  • Bloque TRY: Contiene código protegido que puede generar errores
  • Bloque CATCH: Recibe un objeto de excepción derivado de %Exception.AbstractException
  • Propiedades de la excepción: ex.Name (nombre del error), ex.Code (código del error), ex.Data (datos adicionales), ex.Location (dónde ocurrió el error)
  • Múltiples CATCH: Solo un bloque CATCH por TRY; usar IF/ELSEIF dentro del CATCH para manejar diferentes tipos de error
  • Anidamiento: Los bloques TRY-CATCH pueden anidarse para un manejo de errores más granular
  • Sin nivel de pila: Los bloques TRY no crean un nuevo nivel de pila

Notas Detalladas

Descripción General

TRY-CATCH es el mecanismo de manejo de errores recomendado en ObjectScript moderno. Proporciona un manejo de errores estructurado, legible y mantenible usando objetos de excepción que llevan información detallada sobre qué salió mal y dónde.

Sintaxis Básica de TRY-CATCH

ClassMethod BasicExample()
{
    TRY {
        // Protected code
        Set x = 1 / 0  // Will cause <DIVIDE> error
        Write "This line never executes", !
    }
    CATCH ex {
        Write "Error: ", ex.Name, !           // <DIVIDE>
        Write "Code: ", ex.Code, !            // Error code
        Write "Location: ", ex.Location, !    // Where it happened
        Write "Data: ", ex.Data, !            // Additional info
    }
    Write "Execution continues here", !
}

Propiedades y Métodos del Objeto de Excepción

La variable del CATCH es una instancia de %Exception.AbstractException (o una subclase). Propiedades y métodos clave:

ClassMethod ExamineException()
{
    TRY {
        Set ^ReadOnlyGlobal(1) = "test"  // Assuming <PROTECT> error
    }
    CATCH ex {
        // Properties
        Write "Name:     ", ex.Name, !        // Error name (e.g., <PROTECT>)
        Write "Code:     ", ex.Code, !        // Numeric error code
        Write "Location: ", ex.Location, !    // label+offset^routine
        Write "Data:     ", ex.Data, !        // Context-specific data

        // Methods
        Write "Display:  ", ex.DisplayString(), !  // Full formatted string
        Set sc = ex.AsStatus()                     // Convert to %Status
        Write "Status:   ", $SYSTEM.Status.GetErrorText(sc), !

        // As a SQL code
        Write "SQL Code: ", ex.AsSQLCODE(), !
        Write "SQL Msg:  ", ex.AsSQLMessage(), !
    }
}

Bloques TRY-CATCH Anidados

ClassMethod NestedExample()
{
    TRY {
        Write "Outer TRY", !

        TRY {
            Write "Inner TRY", !
            // Generate an error
            Set x = $PIECE("", ",", -1)  // <FUNCTION> error
        }
        CATCH innerEx {
            Write "Inner CATCH: ", innerEx.Name, !
            // Can rethrow to outer CATCH
            If innerEx.Name = "<SERIOUS>" {
                THROW innerEx
            }
            // Otherwise handle it here
        }

        Write "Continues in outer TRY", !
    }
    CATCH outerEx {
        Write "Outer CATCH: ", outerEx.Name, !
    }
}

Manejo de Diferentes Tipos de Error Dentro del CATCH

ClassMethod HandleByType()
{
    TRY {
        Do ..RiskyOperation()
    }
    CATCH ex {
        If ex.Name = "<DIVIDE>" {
            Write "Division by zero detected", !
        }
        ElseIf ex.Name = "<UNDEFINED>" {
            Write "Undefined variable: ", ex.Data, !
        }
        ElseIf ex.Name = "<SUBSCRIPT>" {
            Write "Invalid subscript access", !
        }
        Else {
            Write "Unexpected error: ", ex.DisplayString(), !
            // Rethrow unexpected errors
            THROW ex
        }
    }
}

Referencias de Documentación

2. Lanzamiento de excepciones

Puntos Clave

  • Comando THROW: Lanza un objeto de excepción, transfiriendo el control al bloque CATCH más cercano
  • %Exception.General: Clase de excepción de propósito general para errores definidos por el usuario
  • $$$ThrowStatus: Macro que lanza una excepción creada a partir de un valor %Status
  • $$$ThrowOnError: Macro que lanza solo si el estado es un error (no hace nada si es OK)
  • Clases de excepción personalizadas: Pueden extender %Exception.AbstractException para errores específicos de la aplicación
  • Relanzamiento: Capturar una excepción y hacer THROW nuevamente para propagarla a un manejador externo

Notas Detalladas

Descripción General

Lanzar excepciones permite señalar condiciones de error explícitamente, en lugar de depender solo de errores generados por el sistema. Esto es esencial para crear aplicaciones robustas con límites de error claros.

Lanzamiento de %Exception.General

ClassMethod ValidateAge(age As %Integer) As %Status
{
    TRY {
        If age < 0 {
            Throw ##class(%Exception.General).%New(
                "InvalidAge",    // Name
                5001,            // Code (application-defined)
                ,                // Location (auto-filled)
                "Age cannot be negative: " _ age)  // Data
        }
        If age > 150 {
            Throw ##class(%Exception.General).%New(
                "InvalidAge", 5001, , "Unrealistic age: " _ age)
        }
        Write "Age is valid: ", age, !
        Return $$$OK
    }
    CATCH ex {
        Write "Validation error: ", ex.Name, !
        Write "Details: ", ex.Data, !
        Return ex.AsStatus()
    }
}

Uso de la Macro $$$ThrowStatus

La macro $$$ThrowStatus convierte un valor %Status en una excepción y la lanza. Esto es esencial para conectar código basado en estados con código basado en excepciones.

Include %occStatus

ClassMethod SaveRecord() As %Status
{
    TRY {
        Set obj = ##class(MyApp.Person).%New()
        Set obj.Name = "John Doe"
        Set sc = obj.%Save()

        // If sc is an error, throw it as an exception
        $$$ThrowOnError(sc)

        Write "Saved successfully with ID: ", obj.%Id(), !
        Return $$$OK
    }
    CATCH ex {
        Write "Save failed: ", ex.DisplayString(), !
        Return ex.AsStatus()
    }
}

$$$ThrowOnError vs $$$ThrowStatus

Include %occStatus

ClassMethod CompareThrowMacros()
{
    TRY {
        Set sc = $$$OK

        // $$$ThrowOnError: Only throws if sc is an error
        // Does NOTHING if sc is $$$OK -- safe to use always
        $$$ThrowOnError(sc)   // No effect, sc is OK

        Set sc = $$$ERROR($$$GeneralError, "Something went wrong")

        // $$$ThrowStatus: ALWAYS throws, even if sc is OK
        // Use this only when you KNOW sc is an error
        // $$$ThrowStatus(sc)  // Would always throw

        // $$$ThrowOnError: Throws because sc is now an error
        $$$ThrowOnError(sc)   // This throws!

        Write "Never reached", !
    }
    CATCH ex {
        Write "Caught: ", ex.DisplayString(), !
    }
}

Relanzamiento de Excepciones

ClassMethod OuterMethod()
{
    TRY {
        Do ..InnerMethod()
    }
    CATCH ex {
        Write "Final handler: ", ex.DisplayString(), !
    }
}

ClassMethod InnerMethod() [ Private ]
{
    TRY {
        // Some risky operation
        Set value = $LISTGET($LISTBUILD(), 5)
    }
    CATCH ex {
        // Log the error
        Set ^ErrorLog($INCREMENT(^ErrorLog)) = ex.DisplayString()
        // Rethrow to let caller handle it
        THROW ex
    }
}

Referencias de Documentación

3. Registro de errores de la aplicación

Puntos Clave

  • Global ^ERRORS: Global del sistema que almacena errores de la aplicación automáticamente cuando ocurren errores no manejados
  • $SYSTEM.OBJ.DisplayError(): Muestra texto de error legible a partir de un valor %Status
  • Management Portal: Visor del registro de errores de la aplicación en System Operation > System Logs > Application Error Log
  • Estructura del error: ^ERRORS almacena nombre del error, ubicación, traza de pila, variables y marca de tiempo
  • ^%ERN: Global de contador que rastrea el número de errores por namespace
  • Registro personalizado: La mejor práctica es complementar el registro del sistema con registros de errores específicos de la aplicación

Notas Detalladas

Descripción General

InterSystems IRIS registra automáticamente los errores no manejados en la global ^ERRORS. Además, los desarrolladores deben implementar un registro de errores estructurado dentro de sus aplicaciones para un diagnóstico completo.

La Global ^ERRORS

Cuando ocurre un error no manejado (sin TRY-CATCH ni $ZTRAP en efecto), IRIS registra el error en la global ^ERRORS en el namespace actual. La estructura contiene:

// Viewing the error log from Terminal
ZWrite ^ERRORS

// Structure of ^ERRORS:
// ^ERRORS(date, index) = errorName
// ^ERRORS(date, index, "m") = stack trace details
// where date is in $HOROLOG format and index is sequential

Registro de Errores de la Aplicación en el Management Portal

Navegar a System Operation > System Logs > Application Error Log para ver una tabla formateada de errores de la aplicación. Esta página muestra:

  • Fecha y hora de cada error
  • Nombre del error (por ejemplo, <UNDEFINED>, <SUBSCRIPT>)
  • Ubicación donde ocurrió el error
  • Namespace donde ocurrió el error
  • ID del proceso y nombre de usuario

Uso de Métodos de $SYSTEM.Status para Mostrar Errores

Include %occStatus

ClassMethod DemonstrateErrorDisplay()
{
    // Create an error status
    Set sc = $$$ERROR($$$GeneralError, "Database connection failed")

    // DisplayError - writes to current device
    Do $SYSTEM.Status.DisplayError(sc)
    // Output: ERROR #5001: Database connection failed

    // GetErrorText - returns error as a string
    Set errorText = $SYSTEM.Status.GetErrorText(sc)
    Write "Error text: ", errorText, !

    // For multi-status errors, get individual components
    Set sc2 = $$$ERROR($$$GeneralError, "Additional problem")
    Set combinedSc = $SYSTEM.Status.AppendStatus(sc, sc2)

    // GetOneStatusText gets a specific error from a compound status
    Set firstError = $SYSTEM.Status.GetOneStatusText(combinedSc, 1)
    Set secondError = $SYSTEM.Status.GetOneStatusText(combinedSc, 2)
    Write "First:  ", firstError, !
    Write "Second: ", secondError, !
}

Registro de Excepciones en el Registro de Errores de la Aplicación

La forma más simple de registrar una excepción capturada en ^ERRORS (visible en el Management Portal y mediante Do ^%ER) es llamar al método .Log() en el objeto de excepción:

TRY {
    // Business logic
    Set result = 100 / 0
}
CATCH ex {
    // Log to ^ERRORS (calls LOG^%ETN internally)
    Do ex.Log()
    // Continue with error handling...
    Return ex.AsStatus()
}

El método %Exception.AbstractException.Log() llama a LOG^%ETN para registrar la excepción en el registro de errores del sistema. Luego se pueden ver los errores registrados:

  • Terminal: Utilidad Do ^%ER
  • Management Portal: System Operation > System Logs > Application Error Log

Este es el enfoque recomendado para registrar excepciones capturadas, ya que las excepciones no manejadas se registran automáticamente pero las excepciones capturadas no se registran a menos que se llame explícitamente a .Log().

Construcción de un Registro de Errores Personalizado de la Aplicación

ClassMethod LogError(
    className As %String,
    methodName As %String,
    ex As %Exception.AbstractException)
{
    Set timestamp = $ZDATETIME($HOROLOG, 3)
    Set key = $INCREMENT(^MyApp.ErrorLog)

    Set ^MyApp.ErrorLog(key, "timestamp") = timestamp
    Set ^MyApp.ErrorLog(key, "class") = className
    Set ^MyApp.ErrorLog(key, "method") = methodName
    Set ^MyApp.ErrorLog(key, "error") = ex.DisplayString()
    Set ^MyApp.ErrorLog(key, "name") = ex.Name
    Set ^MyApp.ErrorLog(key, "code") = ex.Code
    Set ^MyApp.ErrorLog(key, "location") = ex.Location
    Set ^MyApp.ErrorLog(key, "data") = ex.Data

    // Also log the stack trace
    For level = 0:1:$STACK(-1) {
        Set ^MyApp.ErrorLog(key, "stack", level) =
            $STACK(level, "PLACE") _ " : " _ $STACK(level, "MCODE")
    }
}

ClassMethod ProcessData()
{
    TRY {
        // Business logic here
        Set result = 100 / 0
    }
    CATCH ex {
        Do ..LogError("MyApp.Processor", "ProcessData", ex)
        // Optionally rethrow or return error status
        Return ex.AsStatus()
    }
}

Referencias de Documentación

4. $STACK para trazado

Puntos Clave

  • $STACK(-1): Devuelve la profundidad actual de la pila (número de niveles en la pila de ejecución)
  • $STACK(level, "PLACE"): Devuelve la ubicación (etiqueta+desplazamiento^rutina) en el nivel de pila especificado
  • $STACK(level, "MCODE"): Devuelve el código fuente real en el nivel de pila especificado
  • $STACK(level, "ECODE"): Devuelve el código de error en un nivel dado (si ocurrió un error allí)
  • Patrón de bucle: Iterar de 0 a $STACK(-1) para volcar la pila de llamadas completa
  • Uso diagnóstico: Esencial para comprender las cadenas de llamadas durante el manejo de errores

Notas Detalladas

Descripción General

La variable especial $STACK proporciona acceso programático a la pila de llamadas de ejecución. Durante el manejo de errores, $STACK permite capturar una traza completa de la cadena de llamadas que condujo al error, lo cual es invaluable para la depuración.

Uso Básico de $STACK

ClassMethod ShowStack()
{
    Write "Current stack depth: ", $STACK(-1), !
    Write !
    For level = 0:1:$STACK(-1) {
        Write "Level ", level, ": "
        Write $STACK(level, "PLACE")
        Write !
    }
}

Volcado Completo de Pila Durante el Manejo de Errores

ClassMethod MethodA()
{
    TRY {
        Do ..MethodB()
    }
    CATCH ex {
        Write "Error: ", ex.DisplayString(), !
        Write "--- Stack Trace ---", !
        Do ..DumpStack()
    }
}

ClassMethod MethodB() [ Private ]
{
    Do ..MethodC()
}

ClassMethod MethodC() [ Private ]
{
    // Cause an error
    Set x = undefinedVariable  // <UNDEFINED> error
}

ClassMethod DumpStack()
{
    Set depth = $STACK(-1)
    Write "Stack depth: ", depth, !
    For level = 0:1:depth {
        Write "  Level ", level, ":", !
        Write "    PLACE: ", $STACK(level, "PLACE"), !
        Write "    MCODE: ", $STACK(level, "MCODE"), !
        Set ecode = $STACK(level, "ECODE")
        If ecode '= "" {
            Write "    ECODE: ", ecode, !
        }
    }
}

La salida se vería así:

Error: <UNDEFINED>zMethodC+1^MyApp.Debug.1 *undefinedVariable
--- Stack Trace ---
Stack depth: 3
  Level 0:
    PLACE: +1^MyApp.Debug.1
    MCODE: Do ..MethodB()
  Level 1:
    PLACE: zMethodB+1^MyApp.Debug.1
    MCODE: Do ..MethodC()
  Level 2:
    PLACE: zMethodC+1^MyApp.Debug.1
    MCODE: Set x = undefinedVariable
    ECODE: <UNDEFINED>

Referencia de Parámetros de $STACK

SintaxisDevuelve
$STACK(-1)Profundidad actual de la pila (entero)
$STACK(n, "PLACE")Ubicación en el nivel n (etiqueta+desplazamiento^rutina)
$STACK(n, "MCODE")Código fuente en el nivel n
$STACK(n, "ECODE")Código de error en el nivel n (vacío si no hay error)

Integración de $STACK con el Registro de Errores

ClassMethod CaptureStackTrace() As %String
{
    Set trace = ""
    Set depth = $STACK(-1)
    For level = 0:1:depth {
        Set line = "Level " _ level _ ": "
        Set line = line _ $STACK(level, "PLACE")
        Set mcode = $STACK(level, "MCODE")
        If mcode '= "" {
            Set line = line _ " [" _ mcode _ "]"
        }
        Set trace = trace _ line _ $CHAR(10)
    }
    Return trace
}

ClassMethod HandleError()
{
    TRY {
        Do ..SomeOperation()
    }
    CATCH ex {
        Set stackTrace = ..CaptureStackTrace()
        // Store in error log global
        Set key = $INCREMENT(^ErrorLog)
        Set ^ErrorLog(key) = ex.DisplayString()
        Set ^ErrorLog(key, "stack") = stackTrace
        Set ^ErrorLog(key, "time") = $ZDATETIME($HOROLOG, 3)
    }
}

Referencias de Documentación

5. Conversión de códigos de estado de error

Puntos Clave

  • $$$ISERR(sc): Macro que devuelve verdadero (1) si el estado representa un error
  • $$$ISOK(sc): Macro que devuelve verdadero (1) si el estado representa éxito
  • $SYSTEM.Status.GetErrorText(sc): Devuelve una cadena de error legible
  • $SYSTEM.Status.DisplayError(sc): Escribe el texto del error en el dispositivo actual
  • $SYSTEM.Status.GetOneStatusText(sc, n): Devuelve el enésimo error de un estado compuesto
  • $$$ERROR(): Macro para crear un nuevo valor %Status de error con un código de error y mensaje específicos

Notas Detalladas

Descripción General

%Status es un tipo de datos fundamental en InterSystems IRIS utilizado en toda la biblioteca de clases para indicar éxito o fallo de operaciones. Métodos como %Save(), %New(), %Open() y muchos otros devuelven valores %Status. Comprender cómo probar, mostrar y crear valores de estado es esencial.

Prueba de Valores de Estado

Include %occStatus

ClassMethod TestStatus()
{
    Set obj = ##class(Sample.Person).%New()
    Set obj.Name = "Test Person"
    Set sc = obj.%Save()

    // Test if the operation succeeded
    If $$$ISOK(sc) {
        Write "Save succeeded, ID: ", obj.%Id(), !
    }

    // Test if the operation failed
    If $$$ISERR(sc) {
        Write "Save failed!", !
    }

    // IMPORTANT: Never compare %Status directly to 1 or 0
    // WRONG: If sc = 1 { ... }
    // RIGHT: If $$$ISOK(sc) { ... }
}

Mostrar y Extraer Texto de Error

Include %occStatus

ClassMethod DisplayStatusExamples()
{
    // Create an error status for demonstration
    Set sc = $$$ERROR($$$GeneralError, "Connection timeout after 30 seconds")

    // Method 1: Display to current device
    Do $SYSTEM.Status.DisplayError(sc)
    // Output: ERROR #5001: Connection timeout after 30 seconds

    // Method 2: Get as a string (for logging, display elsewhere)
    Set text = $SYSTEM.Status.GetErrorText(sc)
    Write "Error: ", text, !

    // Method 3: Compound status with multiple errors
    Set sc1 = $$$ERROR($$$GeneralError, "First error")
    Set sc2 = $$$ERROR($$$GeneralError, "Second error")
    Set combined = $SYSTEM.Status.AppendStatus(sc1, sc2)

    // Get individual error messages
    Set first = $SYSTEM.Status.GetOneStatusText(combined, 1)
    Set second = $SYSTEM.Status.GetOneStatusText(combined, 2)
    Write "Error 1: ", first, !
    Write "Error 2: ", second, !

    // Get count of errors
    Set count = $SYSTEM.Status.GetErrorCodes(combined)
    Write "Total errors: ", count, !
}

Creación de Valores de Estado de Error

Include (%occStatus, %occErrors)

ClassMethod CreateErrors()
{
    // General error with custom message
    Set sc = $$$ERROR($$$GeneralError, "Custom error message")

    // Error with specific error code
    Set sc = $$$ERROR($$$InvalidArgument, "paramName")

    // Compound status: append multiple errors
    Set sc = $$$OK
    If 'condition1 {
        Set sc = $SYSTEM.Status.AppendStatus(sc,
            $$$ERROR($$$GeneralError, "Condition 1 failed"))
    }
    If 'condition2 {
        Set sc = $SYSTEM.Status.AppendStatus(sc,
            $$$ERROR($$$GeneralError, "Condition 2 failed"))
    }

    Return sc  // Contains all accumulated errors
}

Patrón Común: Verificación del Estado de Retorno

Include %occStatus

ClassMethod RobustSave() As %Status
{
    Set sc = $$$OK

    Set obj = ##class(MyApp.Data).%New()
    Set obj.Field1 = "value1"

    Set sc = obj.%Save()
    If $$$ISERR(sc) {
        // Log and return
        Do $SYSTEM.Status.DisplayError(sc)
        Return sc
    }

    // Continue with more operations
    Set sc = ..AdditionalProcessing(obj.%Id())
    If $$$ISERR(sc) Return sc

    Return $$$OK
}

Referencias de Documentación

6. Estados vs excepciones

Puntos Clave

  • Patrón %Status: Los métodos devuelven %Status, el llamador verifica con $$$ISERR/$$$ISOK -- usado por %Save, %New, %Open
  • Patrón de excepciones: Los errores se lanzan como excepciones, capturados por TRY-CATCH -- usado para errores del sistema y THROW explícito
  • $$$ThrowOnError(sc): Convierte un error %Status en una excepción (puente del mundo de estados al mundo de excepciones)
  • ex.AsStatus(): Convierte una excepción de vuelta a un valor %Status (puente del mundo de excepciones al mundo de estados)
  • %Exception.StatusException: Subclase de excepción creada a partir de un valor %Status
  • Mezcla de patrones: Es común usar excepciones internamente pero devolver %Status a los llamadores

Notas Detalladas

Descripción General

InterSystems IRIS usa dos patrones distintos de señalización de errores: valores de retorno %Status y excepciones. El patrón %Status es ubicuo en la biblioteca de clases (por ejemplo, %Save(), %Open()), mientras que las excepciones se usan para errores en tiempo de ejecución y manejo de errores estructurado moderno. El código del mundo real debe conectar ambos patrones con fluidez.

El Patrón %Status

Include %occStatus

/// Pure %Status style - check every return value
ClassMethod StatusStyle() As %Status
{
    Set sc = $$$OK

    Set obj = ##class(MyApp.Person).%New()
    Set obj.Name = "Test"

    // %Save returns %Status
    Set sc = obj.%Save()
    If $$$ISERR(sc) {
        Do $SYSTEM.Status.DisplayError(sc)
        Return sc
    }

    // %OpenId returns object or "" (with status in second arg)
    Set obj2 = ##class(MyApp.Person).%OpenId(999, , .sc)
    If $$$ISERR(sc) {
        Return sc
    }

    Return $$$OK
}

El Patrón de Excepciones

/// Pure exception style - everything in TRY-CATCH
ClassMethod ExceptionStyle()
{
    TRY {
        Set x = 100 / 0           // <DIVIDE> - system exception
        Set ^data(1) = "value"    // <PROTECT> - system exception
    }
    CATCH ex {
        Write "Caught: ", ex.DisplayString(), !
    }
}

Conversión de %Status a Excepción con $$$ThrowOnError

Include %occStatus

/// Recommended hybrid: Use exceptions internally, return %Status
ClassMethod RecommendedPattern() As %Status
{
    TRY {
        Set obj = ##class(MyApp.Person).%New()
        Set obj.Name = "Test"

        // %Save returns %Status -- convert to exception if error
        Set sc = obj.%Save()
        $$$ThrowOnError(sc)

        // %OpenId with status -- convert to exception if error
        Set obj2 = ##class(MyApp.Person).%OpenId(42, , .sc)
        $$$ThrowOnError(sc)

        // Now both system errors AND status errors are
        // caught by the same CATCH block
        Set result = obj2.Name _ " processed"

        Return $$$OK
    }
    CATCH ex {
        // Single error handling point
        // Convert exception back to %Status for the caller
        Return ex.AsStatus()
    }
}

Conversión de Excepción a %Status

Include %occStatus

ClassMethod ExceptionToStatus() As %Status
{
    TRY {
        // Some operation that may throw
        Do ..RiskyOperation()
        Return $$$OK
    }
    CATCH ex {
        // ex.AsStatus() converts any exception to %Status
        Return ex.AsStatus()
    }
}

Creación de Excepción a Partir de %Status (Explícitamente)

Include %occStatus

ClassMethod CreateStatusException()
{
    Set sc = $$$ERROR($$$GeneralError, "Something failed")

    // Create an exception from a status (without throwing)
    Set ex = ##class(%Exception.StatusException).CreateFromStatus(sc)

    // Now you have an exception object you can inspect
    Write "Name: ", ex.Name, !
    Write "Code: ", ex.Code, !
    Write "Display: ", ex.DisplayString(), !

    // Or throw it
    // THROW ex
}

Comparación Lado a Lado

Include %occStatus

/// Side-by-side: same logic, different patterns
ClassMethod ComparePatterns()
{
    // ===== STATUS PATTERN =====
    Set sc = ..DoWork1()
    If $$$ISERR(sc) {
        Set sc2 = ..DoCleanup()
        If $$$ISERR(sc2) {
            // Compound error - append
            Set sc = $SYSTEM.Status.AppendStatus(sc, sc2)
        }
        Do $SYSTEM.Status.DisplayError(sc)
        Quit
    }

    // ===== EXCEPTION PATTERN =====
    TRY {
        Do ..DoWork2()
    }
    CATCH ex {
        TRY {
            Do ..DoCleanup()
        }
        CATCH cleanupEx {
            // Log cleanup failure too
        }
        Write ex.DisplayString(), !
    }
}

La Plantilla Estándar de Método

Include %occStatus

/// This is the standard recommended pattern for methods
/// that need to return %Status
ClassMethod StandardTemplate(input As %String) As %Status
{
    TRY {
        // Validate input
        If input = "" {
            $$$ThrowStatus($$$ERROR($$$GeneralError, "Input required"))
        }

        // Call methods that return %Status
        Set sc = ..Step1(input)
        $$$ThrowOnError(sc)

        Set sc = ..Step2(input)
        $$$ThrowOnError(sc)

        // Any system error (<UNDEFINED>, <SUBSCRIPT>, etc.)
        // is also caught automatically

        Return $$$OK
    }
    CATCH ex {
        Return ex.AsStatus()
    }
}

Referencias de Documentación

Resumen de Preparación para el Examen

Conceptos Críticos a Dominar:

  1. Sintaxis TRY-CATCH: Saber que CATCH recibe un único objeto de excepción de tipo %Exception.AbstractException
  2. Propiedades de la excepción: Memorizar ex.Name, ex.Code, ex.Data, ex.Location, ex.DisplayString(), ex.AsStatus()
  3. $$$ThrowOnError vs $$$ThrowStatus: ThrowOnError solo lanza en caso de error; ThrowStatus siempre lanza
  4. Global ^ERRORS: Saber que almacena errores no manejados automáticamente y es visible en el Management Portal
  5. $STACK(-1): Devuelve la profundidad de la pila; iterar de 0 a $STACK(-1) con "PLACE" y "MCODE" para la traza completa
  6. $$$ISERR y $$$ISOK: Nunca comparar %Status directamente con 1 o 0; siempre usar estas macros
  7. Puente estado-excepción: $$$ThrowOnError convierte estado a excepción; ex.AsStatus() convierte excepción a estado
  8. Plantilla estándar: Bloque TRY con llamadas $$$ThrowOnError, un solo CATCH que devuelve ex.AsStatus()

Escenarios Comunes de Examen:

  • Dado un código con una verificación de error faltante, identificar qué sucede cuando una operación falla
  • Elegir entre $$$ThrowOnError y $$$ThrowStatus para una situación específica
  • Leer un bloque TRY-CATCH y determinar qué contiene ex.Name o ex.Data para un error dado
  • Identificar la forma correcta de convertir entre %Status y excepciones
  • Determinar qué devuelve $STACK(n, "PLACE") en varios niveles de la pila
  • Reconocer que $SYSTEM.Status.GetErrorText() devuelve una cadena mientras que DisplayError() escribe en el dispositivo

Recomendaciones de Práctica:

  • Escribir un método usando la plantilla estándar TRY-CATCH con $$$ThrowOnError
  • Causar deliberadamente errores , y y examinar el objeto de excepción
  • Crear un método personalizado de registro de errores que capture información de traza con $STACK
  • Practicar la conversión entre %Status y excepciones en ambas direcciones
  • Crear valores %Status compuestos con AppendStatus y extraer errores individuales
  • Navegar al Application Error Log del Management Portal y revisar las entradas
  • Usar $SYSTEM.Status.GetErrorText() y DisplayError() con varios estados de error
  • Implementar bloques TRY-CATCH anidados y observar qué CATCH maneja cada error

Report an Issue