/* SPDX-License-Identifier: BSD-3-Clause */
/*
 * Copyright 2014 Raritan Inc. All rights reserved.
 */

#ifndef __LOG_IDL__
#define __LOG_IDL__

/** Device Logging
 *
 * Log:
 *   - organized as a ring buffer
 *   - divided into multiple log chunks
 *   - size is limited (based on amount of storage and not the message count)
 *   - if size limit is reached then the oldest log messages will be removed (in log chunk granularity)
 *   - real size may vary over time because of optional compression and chunk-wise removal of old messages
 *
 * Log chunk:
 *   - contains log messages
 *   - usually represented by a dedicated file in the backend
 *   - size is limited (based on amount of storage and not the message count)
 *   - real size may vary slightly
 *
 * Log messages:
 *   - have an associated log message id
 *   - the id is not persistent, i.e. id assignment starts from beginning when
 *       - restarting the log service (e.g. by rebooting the device)
 *       - clearing the log
 *
 * Log message id:
 *   - unsigned 32bit integer in the backend
 *   - mapped to a signed 32bit integer in IDL
 *   - when the id reaches 2^31 then the IDL representation of the id will become negative
 *   - at 2^32 the id will wrap to 0
 *   - the id start with 0 and is incremented by 1 with each log message
 *
 * Id reset detection:
 *   1. Retrieve LogInfo via getInfo() and remember the creationTime[2].
 *   2. When retrieving log messages via getChunk() compare the logCreationTime with the creationTime from
 *      getInfo().
 *   3. If they differ then the id numbering has been reset.
 *
 * Log message retrieval:
 *   - only chunk-wise (a chunk is usually represented by a file in the backend)
 *   - one chunk at a time
 *   - when requested start id is in the middle of the chunk then entries before this id are not returned
 *   - when more messages are requested as available in a chunk after the start id then only the available
 *     messages are returned
 *     - requesting 2^31-1 (INT32_MAX) or -1 (2^32-1 (UINT32_MAX) casted to a signed 32bit integer) entries
 *       will ensure you get everything in the requested chunk after the start id
 *   - when going forward: if start id is lower than the first id then the start id is set to the first id
 *   - when going backward: if start id is greater than the last id then the start id is set to the last id
 *
 * Examples:
 *
 *  Retrieving whole log forward from the beginning:
 *
 *    1. Get current log info by calling getInfo() and remember it.
 *    2. Set the start id to idFirst from the log info.
 *    3. Get chunk by calling getChunk(FORWARD) starting at the start id and requesting -1 entries
 *       (see Log message retrieval above for why using -1 here).
 *    4. Compare chunk's logCreationTime with the creationTime from log info. If different then restart whole
 *       retrieval (log service was restarted or log was cleared).
 *    5. Process retrieved log messages if any.
 *    6. If allEntryCnt of the chunk is 0 then stop (the end of the log has been reached).
 *    7. Calculate next start id by adding idFirst and allEntryCnt of the current chunk and go to step 3.
 *
 *  Retrieving whole log backward from the end:
 *
 *    1. Get current log info by calling getInfo() and remember it.
 *    2. If idNext in the logInfo is 0 then stop (log is empty).
 *    3. Set the start id to idNext-1 (i.e. one less then idNext) from the log info.
 *    4. Get chunk by calling getChunk(BACKWARD) starting at the start id and requesting -1 entries
 *       (see Log message retrieval above for why using -1 here).
 *    5. Compare chunk's logCreationTime with the creationTime from log info. If different then restart whole
 *       retrieval (log service was restarted or log was cleared).
 *    6. Process retrieved log messages if any.
 *    7. If idFirst or allEntryCnt of the chunk is 0 then stop (the start of the log has been reached).
 *    8. Calculate next start id by subtracting 1 from idFirst of the current chunk and go to step 4.
 */
module logging {

    /** General log info */
    structure LogInfo {
        long creationTime;      ///< Creation time of log (monotonic clock timestamp).
                                ///<   Changed by clear() and service restart/reboot.
        int idFirst;            ///< Id of first entry of the log
        int idNext;             ///< Next unused entry id of the log
    };

    /** A log entry */
    structure LogEntry {
        int id;                 ///< Entry id
        time timestamp;         ///< Creation time of this entry (UNIX timestamp, UTC)
        string eventClass;      ///< Category (aka event class)
        string message;         ///< Log message
    };

    /** A log chunk */
    structure LogChunk {
        long logCreationTime;   ///< Creation time of log at chunk generation (monotonic clock timestamp)
        int idFirst;            ///< Id of first entry in the chunk
        int allEntryCnt;        ///< Count of all entries in the chunk
        vector<LogEntry> selEntries; ///< Selected entries of the chunk
    };

    /** Range direction when fetching log entries */
    enumeration RangeDirection {
        FORWARD,                ///< Fetch log entries with id, id+1, id+2, ...
        BACKWARD                ///< Fetch log entries with id, id-1, id-2, ...
    };

}

#endif /* __LOG_IDL__ */
