HEC-DSS provides informational messages for operations. The default message level includes file open statements, write statements and error messages, but not read messages. You can set the message level to have HEC-DSS write more or less message information, or turn off messaging all together (although not recommended.) Generally, users need to review the HEC-DSS messages when issues or errors come up; often something as simple as a miss-spelled pathname part.

To better accommodate users, messages are generally directed to a log file, which can be displayed when the user wants to review that file. This is done by calling function zopenLog(const char *logFileName) at the beginning of the program (before other DSS calls.) Before you exit the program, call void zcloseLog().

Message Levels

HEC-DSS version 7 has additional functionality to display messages for specific method types a pre-set levels, so one doesn't get lost in the trees while looking for the forest. Version 7's messaging allows messaging for actions to be elevated without elevating all messaging, so issues can be more easily isolated.

To set the message level for a method set, call the function zsetMessageLevel:

void zsetMessageLevel(int methodID, int levelID);

For example, suppose you were having issues reading time series data. To help diagnose this, you could call zsetMessageLevel like as follows:

zsetMessageLevel(zmessaging_tsread_ID, MESS_LEVEL_USER_DIAG);
….
(DSS time series read calls)
….
zsetMessageLevel(zmessaging_tsread_ID, MESS_LEVEL_GENERAL);

Generally, it is not helpful to go to a level higher than user diagnostics; internal messages usually will clutter output for users trying to determine what issues are. Also, be sure to set the message level back to General when you are out of the area of concern.

Functions

zopenLog

Opens (and creates, if needed) a text file to write all DSS messages to.

Declaration

int zopenLog(const char *logFileName);

Parameters

const char * logFileName

Returns

int status
       STATUS_OKAY for successful operation.
       System error code (a non-zero number) if an error occurred. Not a DSS error code.

zcloseLog

Flushes text to the log file, then closes it.

Declaration

void zcloseLog();

zmessage

Writes a text message to the log file. The message is pre-pended with the date and time, and a CR/NL is added to the end of the message

Declaration

void zmessage(long long *ifltab, const char *message);

Parameters

long long *ifltab
const char *message

Convience Functions

Writes a number after the message

void zmessageInt(long long *ifltab, const char *message, int number);
void zmessageLong(long long *ifltab, const char *message, long long number);

zsetMessageLevel

Controls diagonistic and informational messages from HEC-DSS. Messages are written to the set output, which is either a log file or standard out or another file, if set by the programmer. You can turn on diagnostics for specific kinds of operations using the Method ID.

Declaration

void zsetMessageLevel(int methodID, int levelID);

Parameters

int methodID
int levelID

Method / Group ID

Description

MESS_METHOD_GENERAL

All methods for both DSS version 6 and 7

MESS_METHOD_GLOBAL

All methods for DSS version 7

MESS_METHOD_GET

Low-level read I/O

MESS_METHOD_PUT

Low-level write I/O

MESS_METHOD_READ

Read methods, except time series

MESS_METHOD_WRITE

Write methods, except time series

MESS_METHOD_PERM

Operations for the file header

MESS_METHOD_OPEN

Opening and creating a DSS file

MESS_METHOD_CHECK

Checking for records

MESS_METHOD_LOCKING

Locking and unlocking methods

MESS_METHOD_TS_READ

Time series read operations

MESS_METHOD_TS_WRITE

Time series write operations

MESS_METHOD_ALIAS

Record alias methods

MESS_METHOD_COPY

Record copying functions

MESS_METHOD_UTILITY

General utility functions (rename, delete, etc.)

MESS_METHOD_CATALOG

Cataloging

MESS_METHOD_FILE_CHECK

Checking file integrity

MESS_METHOD_JNI

Java Native Interface


Level ID

Description

MESS_LEVEL_NONE

No messages, including errors (not guaranteed). Highly discourage

MESS_LEVEL_CRITICAL

Critical (Error) messages only. Use discouraged.

MESS_LEVEL_TERSE

Minimal (terse) output: zopen, zclose, critical errors.

MESS_LEVEL_GENERAL

General Log Messages. Default.

MESS_LEVEL_USER_DIAG

Diagnostic User Messages (e.g., input parameters)

MESS_LEVEL_INTERNAL_DIAG_1

Diagnostic Internal Messages level 1 (debug). Not recommended for users

MESS_LEVEL_INTERNAL_DIAG_2

Diagnostic Internal Messages level 2 (full debug)

Example HEC-DSS Logging

#include "heclib.h"

int ExampleLogging()
{
       long long ifltab[250];
       int status;      
       int DEBUG = 1;
       status = zopenLog("C:/temp/Example.log");
       if (status != 0) return status;

       zmessage(ifltab, "Beginning start of program");

       //  Do DSS stuff
       status = zopen(ifltab, "C:/temp/Example.dss");
       if (DEBUG) {
           zmessageInt(ifltab, "Open status: ", status);
       }
       if (status != STATUS_OKAY) return status;

       //  Turn message level up
       zsetMessageLevel(MESS_METHOD_GENERAL_ID, MESS_LEVEL_USER_DIAG);

       zclose(ifltab);
       //  Close log file
       zcloseLog();

       return 0;
}
CODE

Error Handling

Most HEC-DSS functions return a status flag to indicate a successful operation or not. Generally, a return status of 0 (zero, or STATUS_OKAY) indicates a successful operation. A status of -1 (minus one, or STATUS_NOT_OKAY) usually indicates that operation could not be preformed because the record to operate on was not found or similar. DSS does not consider this an "error", just an operation that could not be preformed.

A return status of less than 0 (actually a large negative number) indicates an error, and information about that error is encoded in the status. When such an error is encountered, the calling program needs to take an appropriate action.

The error code will have the format as follows:

-a bb cc dd ee

Where:

  • "a" (0–9) indicates the error severity, with 9 being the highest
  • "bb" (0-99) indicates the highest function called when the error occurred (e.g., ztsStore)
  • "cc" (0-99) indicates the function where the error actually occurred (e.g., zput)
  • "dd" (0-99) is the actual error
  • "ee" (0-99) is the system error code, if the error was returned by the OS

The severity levels and apporopriate actions are as follows:

Severity Level

Value

Meaning

Example

Action

INFORMATION

1

An inconsequential action failed

Unable to unlock a record

None

WARNING

2

Unable to compete the request given

Pathname does not exist

Cannot complete the request given (e.g., data was not read)

INVALID_ARGUMENT

3

An incorrect argument was passed to a function

No pathname provided

Inform user and have them change

WARNING_NO_WRITE_ACCESS

4

You cannot write to the file

You do not have write permission

Inform user and have them change

WARNING_NO_FILE_ACCESS

5

You cannot read or write to the file

Do not have permission

Inform user and have them change

WRITE_ERROR

6

An error was thrown on a write action.

out of disk space

Do not attempt to access the DSS file

READ_ERROR

7

An error was thrown on a read action. The file maybe damaged. It might be recovered by a squeeze, at the user's discretion.

The file maybe damaged.

It might be recovered by a squeeze, at the user's discretion.

CORRUPT_FILE

8

Flags and pointers are not correct, indicating that something has changed the file outside of DSS

Bad ftp transfer or truncated file

Do not attempt to access the DSS file

MEMORY_ERROR

9

Memory exhausted or flags and pointers in memory are not correct

Array out of bounds

Exit, if program did not crash.

Generally, zdssErrorSeverity.WARNING_NO_FILE_ACCESS can be handled by the program and is often associated with a permissions error or network drive that is not available. WRITE_ERROR through CORRUPT_FILE can indicate a bad file or other significant issue. MEMORY_ERROR or CRITICAL_ERROR indicates that something very nasty has occurred and you should exit the program.

HEC-DSS will print any error messages to the log file specified, it the message level is set appropriately. A convenience function "zisError(int status)" will indicate if the status is an error. zerrorCheck will check if an error occurred without needing the status. If an error has occurred, the error information can be obtained by calling function zerror.

Functions

zerrorCheck

zerrorCheck can be called at any time to determine if an error has occurred.

Declaration

int zerrorCheck();

Returns

int status
       0 (Zero) - no error has occurred.
       Severity (1-9) of the error.

zisError

zisError determines if there was an error from the status returned from a DSS function, as opposed to no error or just a warning (such as a record does not exist). If this returns positive, then the program must take appropriate action.

Declaration

int zisError(int status);

Parameters

int status
       The status returned from a DSS function

Returns

int boolError
       0 (Zero) - no error has occurred.
       1 (One) - there has been an error.

Use

If (zisError(status)) {
     // Process the error here
}

zerror

zerror provides all the known information about the last error that occurred. If the message level is set appropriately, this is the same as what has been sent to the log file or standard out. .

Declaration

int zerror(hec_zdssLastError *errorStruct);

Parameters

hec_zdssLastError *errorStruct

The address of an error struct defined in zerrorCodes.h. The program must create this struct. The struct filled out with information about the last error.

Returns

int severity
       0 (Zero) - no error has occurred.
       Severity (1-9) of the error.

errorStruct
       The struct filled out with information about the last error

Error Struct Definition


typedef struct {
       int errorCode;
       int severity;
       int errorNumber;
       int errorType;
       int systemError;
       long long lastAddress;
       int functionID;
       int calledByFunction;
       char errorMessage[MAX_LEN_ERROR_MESS];
       char systemErrorMessage[MAX_LEN_ERROR_MESS];
       char lastPathname[MAX_PATHNAME_SIZE];
       char filename[MAX_FILENAME_LENGTH];

} hec_zdssLastError;
CODE


Example: Simple Error Processing

function zcheck returns either STATUS_RECORD_FOUND, STATUS_RECORD_NOT_FOUND or an error code.

status = zcheck(ifltab, pathname);
if (zisError(status)) {
    zerror(&errorStruct);
    notifyUser(&errorStruct); // (e.g., display an error dialog)
    if (zerrorSeverity(status) >= zdssErrorSeverity.MEMORY_ERROR) exitProg();
    return status;
}
If(status == STATUS_RECORD_NOT_FOUND) {
    printf("Record does not exist: %s\n", pathname);
    return status;
}
// Process data set
CODE

Example: Error Processing

You may want to copy portions of this example directly into your program.


#include <string.h>
#include "heclib.h"
void notifyUser(hec_zdssLastError *errorStruct);

int ExampleErrorHandling()
{
       long long ifltab[250];    
       int status;
       hec_zdssLastError errorStruct;
       zStructTimeSeries *tss;

       //  Open a log file for messages and transactions
       status = zopenLog("C:/temp/Example.log");
       if (status != 0) return status;

       //  Create some errors to show process
       //  Bad drive or file name
       status = zopen(ifltab, "Z:/temp/Example7.dss");
       if (zisError(status)) {
             //  The error message is automatically written to the log file,
             //  so the following 2 lines are optional
             zerror(&errorStruct);
             notifyUser(&errorStruct);   //  (e.g., display an error dialog)
             if (zerrorSeverity(status) >= zdssErrorSeverity.MEMORY_ERROR) exit(0);
             //  return status;
       }

       //  Okay, open a valid file
       zerrorStructClear();
       printf("\n\n");
       status = zopen(ifltab, "C:/temp/Example7.dss");
       if (zisError(status)) {
             zerror(&errorStruct);
             notifyUser(&errorStruct);  
             if (zerrorSeverity(status) >= zdssErrorSeverity.MEMORY_ERROR) exit(0);
             //  return status;
       }

       //  Create a new error by writing a time series struct with no pathname
       tss = zstructTsNew("");
       status = ztsStore(ifltab, tss, 0);
       if (zisError(status)) {
             //  The error message is automatically written to the log file,
             //  so the following 2 lines are optional
             zerror(&errorStruct);
             notifyUser(&errorStruct);   //  (e.g., display an error dialog)
             zstructFree(tss);
             if (zerrorSeverity(status) >= zdssErrorSeverity.MEMORY_ERROR) exit(0);
             //  return status;
       }

       //  Do stuff with struct, then free
       zstructFree(tss);

       //  When all done (near end of program), close the file
       zclose(ifltab);
       zcloseLog();

       return 0;
}

void notifyUser(hec_zdssLastError *errorStruct)
{
       if (errorStruct->severity == 0) {
             return;
       }
       else if (errorStruct->severity < zdssErrorSeverity.INVALID_ARGUMENT) {
             printf("*** Warning ***\n");
       }
       else if (errorStruct->severity < zdssErrorSeverity.WRITE_ERROR) {
             printf("*** File access error ***\n");
       }
       else if (errorStruct->severity == zdssErrorSeverity.WRITE_ERROR) {
             printf("*** Write error ***\n");
       }
       else if (errorStruct->severity < zdssErrorSeverity.MEMORY_ERROR) {
             printf("*** Read or File corruption error ***\n");
       }
       else {
             printf("*** Critical error ***\n");
       }      

       if (strlen(errorStruct->errorMessage) > 2) {
             printf("Error: %s\n", errorStruct→errorMessage);
       }
       if (strlen(errorStruct->systemErrorMessage) > 2) {
             printf("System error: %s\n", errorStruct→systemErrorMessage);
       }
       if (strlen(errorStruct->lastPathname) > 2) {
             printf("Last pathname: %s\n", errorStruct→lastPathname);
       }
       if (strlen(errorStruct->filename) > 2) {
             printf("File: %s\n", errorStruct→filename);
       }     

}
CODE


Output:

*** File access error ***
Error: *****DSS*** ERROR in function zopen: Unable to create file
File
Z:\temp\Example7.dss
System error: No such file or directory

*** File access error ***
Error: -----DSS--- ztsStore  Warning: Invalid pathname
pathname:
Invalid pathname
File: C:\temp\Example7.dss

Mulitple Processes Access

A principal feature of HEC-DSS is that several processes (multi-user) can read and write data to a single database at the same time. The multi-user access capability is implemented with system record locking and flushing functions. There is no daemon or other background program managing accesses to a database. A database may also exist on a Windows or Unix server, which can be accessed by users on PC's or other computers via the network.

Multi-user access is automatic and needs no action from the programmer or user. When HEC-DSS detects another processes accessing a file, writes by either (any) process to that file are flushed to disk to ensure that the other processes coordinate with that. This allows one program to access what another program wrote. However, this flushing to disk on the Windows OS takes significantly longer (on the order of 100 times) than single user access. This is not true on some Unix workstations. It is recommended, when possible, to keep in a single user access mode on Windows PCs by accessing a file from only one vitural machine.

Reading from a DSS file being written to by another process

There is little measurable impact reading from or listening to a HEC-DSS file that is being written to by another process. You can watch a DSS file for changes, and read those changes, with little time impact. Refer to the listener discussion and example later in this document.

Common Utility Functions

zpathnameForm

zpathnameForm builds a pathname from the 6 (input) parts.

Declaration

int zpathnameForm(const char *aPart, const char *bPart, const char *cPart, const char *dPart, 
                                const char *ePart, const char *fPart, char *pathname, size_t sizeofPathname);

Parameters

const char *aPart - const char *fPart
       The six pathname parts to be formed into a pathname \

char *pathname
       A character string to return the pathname in

size_t sizeofPathname
       The size of pathname in bytes.

Returns

int length
       0 (Zero) - no error has occurred.
       1 (One) - there has been an error.

Use

If (zisError(status)) {
       // Process the error here
}