status = false; try { register_shutdown_function(array($this, '__destruct')); $this->errStack = []; $this->haveErrors = false; $this->haveWarnings = false; $this->haveFatals = false; $this->publishMessage = $_pm; $this->eventGUID = (!is_null($_eg) and validateGUID($_eg)) ? $_eg : null; $this->validTemplates = [TEMPLATE_CLASS_LOGS, TEMPLATE_CLASS_METRICS]; // toss a fatal if the config hasn't been instantiated... if (!isset(gasConfig::$settings) or empty(gasConfig::$settings)) { $this->throwFatal(__FILE__ . '(' . __LINE__ . '): ' . ERROR_CONFIG_404); } elseif (empty(gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_MONGODB])) { $this->throwFatal(__FILE__ . '(' . __LINE__ . '): ' . ERROR_CONFIG_RESOURCE_404 . RESOURCE_DDB); } // $this->config = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_DDB]; // $this->connection = $this->getNoSQLResource(); // ddb connection $this->config = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_MONGODB]; $this->connection = gasResourceManager::fetchResource(RESOURCE_MONGO_MASTER, ENV_ADMIN); $this->available = (!is_null($this->connection)) ? true : false; $this->env = gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV]; $this->dbName = $this->env . UDASH . $this->config[CONFIG_DATABASE_MONGODB_ADMIN][CONFIG_DATABASE_MONGODB_DB_NAME]; // $this->abc = null; $this->status = true; } catch (TypeError | Throwable $e) { $hdr = basename(__METHOD__) . AT . __LINE__ . COLON; echo getDateTime() . CON_ERROR . $this->res . $hdr . $e->getMessage(); } } /** * setService() -- public method * * When any class that extends core creates an embedded logger class, which they all should, then the instantiation * class should call this function s.t. the logger class inherits (sloppily) the service defined for the current * class. This will validated later in the function: isServiceLocal() when we're instantiating a class to ensure * that a class can only be instantiated in it's service when we're dealing with appServer and tercero classes. * * There is a single input parameter to the function that is the defined name of the current service. We're not * validating this string value b/c that's happened already within the "parent" class. * * @author mike@givingassistant.org * @version 1.0 * * @param string $_service * @return bool * * HISTORY: * ======== * 11-04-20 mks DB-171: original coding * */ public function setService(string $_service):bool { if (isset(gasConfig::$settings[$_service])) if (gasConfig::$settings[$_service][CONFIG_IS_LOCAL]) $this->service = $_service; else { $hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__); $msg = sprintf(ERROR_SERVICE_NOT_LOCAL, $_service); consoleLog('SSER: ', CON_ERROR, $hdr . $msg); return false; } else { $hdr = sprintf(INFO_LOC, basename(__METHOD__), __FILE__); $msg = ERROR_CONFIG_RESOURCE_404 . STRING_SERVICE; consoleLog('SSER: ', CON_ERROR, $hdr . $msg); return false; } return true; } /** * throwFatal() -- private method * * if the logger cannot be properly instantiated, (thereby being unable to log errors in the database), the the * last remaining option is to throw a direMessage (tm) to the console. * * * @author mike@givingassistant.org * @version 1.0 * * @param string $_msg -- the text dumped to the php-errors log * @throws Exception * * HISTORY: * ======== * 06-07-17 mks original coding * 12-07-17 mks CORE-591: removed errStack dump b/c cached and can be recovered * 01-22-18 mks _INF-139: updated code to php 7.2 * 03-02-18 mks CORE-680: deprecated trace logging * */ private function throwFatal(string $_msg): void { $msg = PHP_EOL . '----------------------------------------------------------------------------------------------------' . PHP_EOL; $msg .= ' FATAL ERRORS OCCURRED IN THE ERROR CLASS. EVALUATE, FIX, AND RE-RUN.' . PHP_EOL; $msg .= PHP_EOL . $_msg . PHP_EOL; $msg .= '----------------------------------------------------------------------------------------------------' . PHP_EOL; throw new Exception($msg); } public function debug(string $_message): void { try { self::set(ERROR_DEBUG, $_message); } catch (Throwable $t) { $msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage(); consoleLog($this->res, CON_ERROR, $msg); } } public function info(string $_message): void { try { self::set(ERROR_INFO, $_message); } catch (Throwable $t) { $msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage(); consoleLog($this->res, CON_ERROR, $msg); } } public function data(string $_message): void { try { self::set(ERROR_DATA, $_message); } catch (Throwable $t) { $msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage(); consoleLog($this->res, CON_ERROR, $msg); } } public function error(string $_message): void { try { self::set(ERROR_ERROR, $_message); } catch (Throwable $t) { $msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage(); consoleLog($this->res, CON_ERROR, $msg); } } public function warn(string $_message): void { try { self::set(ERROR_WARN, $_message); } catch (Throwable $t) { $msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage(); consoleLog($this->res, CON_ERROR, $msg); } } public function fatal(string $_message): void { try { self::set(ERROR_FATAL, $_message); } catch (Throwable $t) { $msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage(); consoleLog($this->res, CON_ERROR, $msg); } } public function metrics(string $_message, float $_time, &$_es = null): void { try { self::set(ERROR_METRICS, $_message, true, $_time, $_es); } catch (Throwable $t) { $msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage(); consoleLog($this->res, CON_ERROR, $msg); } } /** * set() -- public method * * this method is where most of the work gets done for the class. * * this method accepts a log level and a log message. if AMQP and nosql services are not available (either), * then the message will be output to the console. * * otherwise, we're going to parse the log level against the configuration settings to ensure that we're * publishing messages according to the settings and the current environment. (iow, don't publish debug level * messages while in a production environment) * * RULES: * ------ * DEBUG errors are only logged if debug mode is on * * we use debug_backtrace to generate the originating message data points and assemble the message data * (and the meta data for the broker request) into a single array which is then processed and published * to the delayed-write queue (itself a fire-and-forget queue). * * this design differs from previous iterations in that we're no longer trying to preserve an ongoing error * stack - instead we're just considering the incoming message to be the only message currently in existence. * * The input parameters to the method are: * * $_level - which is the message level and a defined constant * $_message - the text of the actual message * $_metrics - (optional, default = false) if true, use the metrics template instead of the logs template * $_t - (optional, default = 0), for metrics, the total query time * $_es - (optional, default = 0), call-by-reference param to store/return the metrics error stack * * There are no return values, either implicitly or explicitly. * * @author mike@givingassistant.org * @version 1.0 * * @param string $_level error level * @param string $_message error message string * @param bool $_metrics defines the event as a metric (instead of an error) event * @param float $_t time, in ms * @param array $_es error stack: call by reference array stack/container * @throws Exception * * * HISTORY: * ======== * 06-07-17 mks original coding * 07-12-17 mks added log-level values to collection/processing * 12-08-17 mks CORE-591: new throw-fatal processing * 03-02-18 mks CORE-680: deprecated trace logging * 06-08-18 mks CORE-1034: deprecating XML prodBox tag * 07-30-18 mks CORE-774: PHP7.2 exception handling update * 09-24-19 mks DB-136: fixed error in levelValues element assignment to correct constant * 11-04-20 mks DB-171: added service (origin) definition to logging output * */ private function set(string $_level, string $_message, bool $_metrics = false, float $_t = 0, array &$_es = null): void { $this->errStack = []; $levelValues = [ ERROR_EVENT => ERROR_EVENT_VAL, ERROR_METRICS => ERROR_METRICS_VAL, ERROR_DEBUG => ERROR_DEBUG_VAL, ERROR_DATA => ERROR_DATA_VAL, ERROR_INFO => ERROR_INFO_VAL, ERROR_ERROR => ERROR_ERROR_VAL, ERROR_WARN => ERROR_WARN_VAL, ERROR_FATAL => ERROR_FATAL_VAL ]; if (!array_key_exists($_level, $levelValues)) { $this->throwFatal(__FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UNKNOWN_KEY, $_level, LOG_VALUE)); $_level = ERROR_ERROR; } // the system is up - so create the error message request for publication to the DW broker $_message = empty($_message) ? ERROR_DATA_INPUT_EMPTY : trim($_message); switch ($_level) { case ERROR_DEBUG : $saveError = gasConfig::$settings[CONFIG_DEBUG] and !(gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] == ENV_PRODUCTION); break; case ERROR_DATA : case ERROR_INFO : case ERROR_METRICS : $saveError = true; break; case ERROR_ERROR : $this->haveErrors = true; $saveError = true; break; case ERROR_WARN : $this->haveWarnings = true; $saveError = true; break; case ERROR_FATAL : $this->haveFatals = true; $saveError = true; break; default : $saveError = true; $_level = ERROR_INFO; break; } if (!$saveError) return; try { if ($_level == ERROR_METRICS) { $this->isMetric = true; $this->setCollection(TEMPLATE_CLASS_METRICS); } else { $this->setCollection(); } } catch (Throwable $t) { consoleLog($this->res, CON_ERROR, ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage()); } if (is_array($_message)) { $_message = implode('
', $_message); } $backTrace = debug_backtrace(); for ($index = 0; $index < 3; $index++) { if (isset($backTrace[$index][STRING_FUNCTION]) and $backTrace[$index][STRING_FUNCTION] != STRING_SET) break; } // if (isset($backTrace[2][ERROR_FILE])) { // $index = 2; // } elseif (isset($backTrace[1][ERROR_FILE])) { // $index = 1; // } else { // $index = 0; // } $errStack = null; if (empty($this->errStack)) $this->errStack = array(); if ($_level == ERROR_METRICS) @$errStack[(LOG_EVENT . $this->ext)] = EVENT_METRICS; @$errStack[(LOG_FILE . $this->ext)] = $this->service . ARROW . $backTrace[$index][ERROR_FILE]; @$errStack[(LOG_LINE . $this->ext)] = $backTrace[$index][ERROR_LINE]; @$errStack[(LOG_METHOD . $this->ext)] = $backTrace[$index+1][STRING_FUNCTION]; @$errStack[(LOG_CLASS . $this->ext)] = $backTrace[$index+1][ERROR_CLASS]; @$errStack[(LOG_LEVEL . $this->ext)] = $_level; @$errStack[(LOG_VALUE . $this->ext)] = $levelValues[$_level]; @$errStack[(LOG_MESSAGE . $this->ext)] = utf8_encode($_message); if (isset($this->eventGUID)) @$errStack[(DB_EVENT_GUID . $this->ext)] = $this->eventGUID; if ($_metrics) { @$errStack[(LOG_TIMER . $this->ext)] = $_t; $_es = $backTrace; } $errStack[(LOG_CREATED . $this->ext)] = time(); array_push($this->errStack, $errStack); try { $this->writeLogMessage(); if ($this->mirror) { consoleLog($this->res, CON_ERROR, $_message); } } catch (Throwable $t) { consoleLog($this->res, CON_ERROR, ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage()); } } /** * writeLogMessage() -- public static method * * this is the record-create method for saving a log event. * * There are three input parameters to the method, all of which are required: * * $_data -- the data payload as received by the broker in associative array format * $_meta -- the meta payload as received by the broker in associative array format * $_where -- string (use the system constant, please) that defines the collection destination * * first thing we do is set the collection destination by passing the $_where input parameter to the * private setCollection() method. * * if we (self) are not available, then return immediately where the calling client should assume that the * logging services are not available and post the necessary console message. * * Validate the $_data payload by assigning the contents, filtering the payload through a validation array, * into a temp variable... * * next, insert the generated sequence key into the temp array structure and add the created-date timestamp... * * finally, insert the record into the designated collection, trapping any nosql exception raised in our fatal * handler so that the (error) results are saved to the console log. * * @author mike@givingassistant.org * @version 1.0 * * @param bool $_im -- is Metric -- should only be set to true from adminIn broker event call * @throws Exception * * HISTORY: * ======== * 06-07-17 mks original coding * 06-14-17 mks refactored for dynamodb * 07-05-17 mks CORE-463: refactored for RMQ and mongoDB * 07-07-17 mks CORE-463: switch collections on-the-fly for adminIn Metrics event call * 12-06-17 mks CORE-591: caching log messages based on XML config params, w/console logging on errors * 01-22-18 mks _INF-139: fixed bug where when caching is disabled, the current error wasn't being * added to the error stack. * 03-01-18 mks CORE-689: removed env tag from collection name * 07-30-18 mks CORE-774: converted to PHP7.2 typeError trapping/processing * */ public function writeLogMessage(bool $_im = false) { // if the logger service is unavailable or we don't have a message to publish, then return if (!$this->available or empty($this->errStack)) return; $this->status = false; $oe = $oc = $os = ''; $maxMsgCount = gasConfig::$settings[CONFIG_CACHE][CONFIG_CACHE_LOG_BUFFER_COUNT]; $msgBufferOn = boolval(gasConfig::$settings[CONFIG_CACHE][CONFIG_CACHE_LOG_BUFFER]); $whichBuffer = ($this->isMetric) ? CONFIG_CACHE_METRICS_BUFFER : CONFIG_CACHE_LOG_BUFFER; $whichBufferCounter = ($this->isMetric) ? CONFIG_CACHE_METRICS_BUFFER_COUNT : CONFIG_CACHE_LOG_BUFFER_COUNT; // if (empty($aryData[DB_PKEY])) { // $this->errStack[(DB_PKEY . $this->ext)] = guid(); // } // $this->errStack[(LOG_CREATED . $this->ext)] = time(); // admin service is remote - either cache or publish the message if ($this->publishMessage) { try { $currMsgCount = gasCache::sysGet($whichBufferCounter); $msgBuffer = gasCache::sysGet($whichBuffer); // remove cache data gasCache::sysDel($whichBuffer); gasCache::sysDel($whichBufferCounter); } catch (Throwable $t) { $msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage(); consoleLog($this->res, CON_ERROR, $msg); return; } // validate the message buffer fetched from cache if (!empty($msgBuffer) and !is_array($msgBuffer)) { $msg = basename(__FILE__) . COLON . __LINE__ . COLON; $msg .= sprintf(ERROR_CACHE_DATA_MALFORMED, 'array', CONFIG_CACHE_LOG_BUFFER, gettype($msgBuffer)); $msg .= PHP_EOL . 'Dump: ' . PHP_EOL; $msg .= var_export($msgBuffer, true); $msg .= PHP_EOL; $this->throwFatal(basename(__METHOD__) . AT . __LINE__ . COLON . $msg); return; } if ($currMsgCount === false) { /** @noinspection PhpUnusedLocalVariableInspection */ $currMsgCount = 0; } if (false === $msgBuffer) $msgBuffer = []; $msgBuffer = [...$msgBuffer, ...$this->errStack]; $currMsgCount = count($msgBuffer); // determine if we're going to publish or cache the message buffer $publish = (!$msgBufferOn or $currMsgCount >= $maxMsgCount) ? true : false; if ($publish) { try { // $this->abc = new gacAdminClientIn(__METHOD__ . COLON . __LINE__); $this->abc = new gacLogClient(); if (!$this->abc->status) { $hdr = basename(__METHOD__) . AT . __LINE__ . COLON; $msg = ERROR_FAILED_TO_INSTANTIATE . RESOURCE_ADMIN_CLIENT; consoleLog($this->res, CON_ERROR, $hdr . $msg); return; } } catch (Throwable $t) { $msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage(); consoleLog($this->res, CON_ERROR, $msg); return; } $request = [ BROKER_REQUEST => ($this->isMetric) ? BROKER_REQUEST_MET : BROKER_REQUEST_LOG, BROKER_DATA => $msgBuffer, BROKER_META_DATA => [ META_TEMPLATE => ($this->isMetric) ? TEMPLATE_CLASS_METRICS : TEMPLATE_CLASS_LOGS, META_CLIENT => CLIENT_SYSTEM ] ]; if (!empty($this->eventGUID)) $request[BROKER_META_DATA][META_EVENT_GUID] = $this->eventGUID; try { $route = (!$this->isMetric) ? EXCHANGE_SOURCE_LOGS : EXCHANGE_SOURCE_METRICS; $this->abc->call(gzcompress(json_encode($request)), $route); if (is_object($this->abc)) $this->abc->__destruct(); unset($this->abc); } catch (TypeError | Throwable $t) { $hdr = basename(__METHOD__) . AT . __LINE__ . COLON; consoleLog($this->res, CON_ERROR, $hdr . $t->getMessage()); return; } unset($this->abc); // $this->abc = null; $this->isMetric = false; // if (gasConfig::$settings[CONFIG_DEBUG]) { // $msg = sprintf(SUCCESS_CACHE_LOG_DUMP, $currMsgCount); // consoleLog($this->res, CON_SUCCESS, $msg); // } } else { // update the current message buffer and message buffer counter and re-cache $msgBuffer = [...$msgBuffer, ...$this->errStack]; $currMsgCount = count($msgBuffer); try { if (!gasCache::sysAdd($whichBuffer, $msgBuffer)) { $this->throwFatal(basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_CACHE_ADD_FAIL . $whichBuffer); return; } if (!gasCache::sysAdd($whichBufferCounter, $currMsgCount)) { $this->throwFatal(basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_CACHE_ADD_FAIL . $whichBufferCounter . COLON . $currMsgCount); return; } } catch (Throwable $t) { $msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage(); consoleLog($this->res, CON_ERROR, $msg); return; } } } else { // write the message directly to mongodb - start by checking the mongo resource if (is_null($this->connection)) { // if we "lost" the resource, attempt to reconnect $this->connection = gasResourceManager::fetchResource(RESOURCE_MONGO_MASTER, ENV_ADMIN); // if we can't reconnect, throw a fatal and exit if (is_null($this->connection)) { $this->throwFatal(basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_MONGO_CONNECT); } } try { $record = new MongoDB\Driver\BulkWrite(); foreach ($this->errStack as $errorMessage) $record->insert($errorMessage); if ($_im) { $oc = $this->collectionName; $oe = $this->ext; $os = $this->class; $this->ext = COLLECTION_MONGO_METRICS_EXT; $this->collectionName = COLLECTION_MONGO_METRICS . $this->ext; $this->class = COLLECTION_MONGO_METRICS; } else { $this->ext = COLLECTION_MONGO_LOGS_EXT; $this->collectionName = COLLECTION_MONGO_LOGS . $this->ext; $this->class = COLLECTION_MONGO_LOGS; } /** @var WriteResult $result */ $result = $this->connection->executeBulkWrite($this->dbName . DOT . $this->collectionName, $record); if ($_im) { $this->ext = $oe; $this->collectionName = $oc; $this->class = $os; } unset($record); if ($result->getInsertedCount() != 1) { $msg = __CLASS__ . COLON . __LINE__ . COLON; $msg .= sprintf(ERROR_MONGO_INSERT_COUNT, 1, $result->getInsertedCount()); echo getDateTime() . CON_ERROR . $this->res . $msg . PHP_EOL; // todo -- eventManger should be invoked here } else { $this->status = true; } } catch (MongoDB\Driver\Exception\BulkWriteException $e) { $this->throwFatal(basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_MONGO_EXCEPTION_BULK_WRITE . PHP_EOL . $e->getMessage()); } catch (MongoDB\Driver\Exception\InvalidArgumentException $e) { $this->throwFatal(basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_MONGO_EXCEPTION_INVALID_ARGS . PHP_EOL . $e->getMessage()); } catch (MongoDB\Driver\Exception\ConnectionException $e) { $this->throwFatal(basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_MONGO_EXCEPTION_CONNECTION . PHP_EOL .$e->getMessage()); } catch (MongoDB\Driver\Exception\RuntimeException $e) { $this->throwFatal(basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_MONGO_EXCEPTION_RUNTIME . PHP_EOL . $e->getMessage()); } } } /** * setCollection() -- private method * * this is a private method, always called by the writeLogMessage() method, that sets the collection destination * for the current request. As of this writing, the logger handles all writes to both the log (pgsLogs_log) and * metrics (pgsMetrics_met) collections. Based on the data passed in the error-message, we set the collection * destination in this method, along with other member variables that are collection dependent. * * the method has a single input parameter, which defaults to a known constant, that is the destination collection. * * @author mike@givingassistant.org * @version 1.0 * * @param string $_which * @throws Exception * * HISTORY: * ======== * 06-07-17 mks original coding * 06-14-17 mks updated for ddb, dynamic environments * 07-05-17 mks CORE-463: converted to mongodb * 03-01-18 mks CORE-689: removed env tags from db name * */ private function setCollection(string $_which = TEMPLATE_CLASS_LOGS): void { if (!in_array($_which, $this->validTemplates)) { $this->throwFatal(ERROR_INVALID_TEMPLATE . $_which); } else { if ($_which == TEMPLATE_CLASS_LOGS) { $this->ext = COLLECTION_MONGO_LOGS_EXT; $this->collectionName = COLLECTION_MONGO_LOGS . $this->ext; $this->class = COLLECTION_MONGO_LOGS; } else { $this->ext = COLLECTION_MONGO_METRICS_EXT; $this->collectionName = COLLECTION_MONGO_METRICS . $this->ext; $this->class = COLLECTION_MONGO_METRICS; } } } /** * getLog() - public method * * getLog is the method that is used to fetch log (or Metrics) records from the mongo collection. * * The method has two required parameters: * * $_lines - integer value that indicates the number of log entries to retrieve - defaults to the system constant * $_where - defines which collection to fetch from * * Method opens a channel/connection to mongodb and fetches N lines from the collection specified by the * input parameter. * * @author mike@givingassistant.org * @version 1.0 * * @param int $_lines * @param string $_where * @return null|string * @throws Exception * * HISTORY: * ======== * 07-05-17 mks CORE-463: original coding * 09-08-17 mks CORE-529: added event guids to the generated output for dumper * 07-30-18 mks CORE-774: PHP7.2 Exception Compliance * */ public function getLog($_lines, $_where): ?string { if (!in_array($_where, $this->validTemplates)) { $msg = ERROR_MONGO_TEMPLATE_INVALID . $_where; return($msg); } try { $this->setCollection($_where); } catch (Throwable $t) { consoleLog($this->res, CON_ERROR, ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage()); } if (!$this->available) { return(null); // returning on false implicitly generates a console error message by the calling client } if (!is_numeric($_lines) or $_lines < 0) { $_lines = intval(MONGO_LOG_MAX_LINES); } else { $_lines = intval($_lines); } $mongoData = null; $returnData = null; $cursor = null; try { $options = [ STRING_SORT => [(LOG_CREATED . $this->ext) => -1], STRING_LIMIT => $_lines ]; $filter = []; $nameSpace = $this->dbName . DOT . $this->collectionName; $readPreference = new MongoDB\Driver\ReadPreference($this->config[CONFIG_DATABASE_MONGODB_ADMIN][CONFIG_DATABASE_MONGODB_SECONDARY_RP]); $query = new MongoDB\Driver\Query($filter, $options); $cursor = $this->connection->executeQuery($nameSpace, $query, $readPreference); } catch (Throwable | TypeError $e) { $this->throwFatal(__FILE__ . COLON . __LINE__ . COLON . ERROR_MONGO_EXCEPTION_INVALID_ARGS . PHP_EOL . $e->getMessage()); } if (!is_null($cursor)) { foreach ($cursor as $property) { $property = (array) $property; $returnData .= '
'; // note: css is defined in the utilities directory $returnData .= getDateTime($property[(LOG_CREATED . $this->ext)]) . ' - '; // $returnData .= date(TIME_DATE_FORMAT, $row[(META_SESSION_DATE . self::$ext)]->sec) . ' - '; // add error label as a span: warn/error/fatal... try { $returnData .= self::getErrorLabel($property[(LOG_LEVEL . $this->ext)]); } catch (TypeError $t) { consoleLog($this->res, CON_ERROR, ERROR_TYPE_EXCEPTION . COLON . $t->getMessage()); } $returnData .= ' ' . $property[(ERROR_FILE . $this->ext)] . '(' . $property[(ERROR_LINE . $this->ext)] . ')'; $cd = ''; if (!empty($property[(ERROR_CLASS . $this->ext)])) $cd = ' class[' . $property[(ERROR_CLASS . $this->ext)] . ']'; if (!empty($property[(ERROR_METHOD . $this->ext)])) $cd .= '.method(' . $property[(ERROR_METHOD . $this->ext)] . ')
'; $returnData .= $cd; $returnData .= '
' . htmlentities($property[(ERROR_MESSAGE . $this->ext)]); if ($_where == TEMPLATE_CLASS_METRICS) { $returnData .= ' - ' . $property[(DB_TIMER . $this->ext)] . ' or '; $returnData .= ($property[(DB_TIMER . $this->ext)] * NUMBER_MS_PER_SEC) . 'ms'; } $returnData .= '
'; $returnData .= '
'; if (!empty($property[(DB_EVENT_GUID . $this->ext)])) { $returnData .= 'Event ID: ' . $property[(DB_EVENT_GUID . $this->ext)]; } // foreach($row[(TEMPLATE_HISTORY . $this->ext)] as $histRec) { // $returnData .= date('Y-M-d h:i:s', $histRec[META_SESSION_DATE]->sec);// . ' ('; // if (!is_null($row[(MONGO_LOG_EVENT_GUID . $this->ext)])) // $returnData .= ', Event ID: ' . $row[(MONGO_LOG_EVENT_GUID . $this->ext)]; // $returnData .= $histRec[META_SESSION_EVENT] . ') from ('; // $returnData .= $histRec[META_SESSION_IP] . '): '; // $returnData .= ((isset($histRec[META_SESSION_ID])) ? $histRec[META_SESSION_ID] : $histRec[META_CLIENT_ID]) . '
'; // } $returnData .= '

'; } } return ($returnData); } /** * getErrorLabel() - public method * * build an association between known error types and a color-key for output. * * if the error does not exist, return black. * * in all cases, return an HTML SPAN tag coded to the selected color. * * @author mike@givingassistant.org * @version 1.0 * * @param $errorType * @return string * * HISTORY: * ======== * 06-07-17 mks original coding * */ private function getErrorLabel(string $errorType):string { // set the error level text-color $errorColorMap = [ ERROR_DEBUG => '#008000', // green ERROR_METRICS => '#00FF00', // black ERROR_DATA => '#0000FF', // black ERROR_INFO => '#000080', // navy ERROR_ERROR => '#800080', // purple ERROR_FATAL => '#FF0000', // red ERROR_WARN => '#F47E1C', // orange, ERROR_EVENT => '#FF00CC', // pink ]; $cssColor = (!empty($errorColorMap[$errorType])) ? $errorColorMap[$errorType] : '#0'; return '' . strtoupper($errorType) . ''; } /** * __clone() -- public method * * Silently disallows cloning of the object * * @author mike@givingassistant.org * @version 1.0 * * @return null * * HISTORY: * ======== * 03-18-15 mks original coding * */ private function __clone() { return null; } /** * __destruct() -- public method * * As of PHP 5.3.10, destructors are not run on shutdowns caused by fatal errors - since the destructor is * now registered in the constructor method, recovery and/or clean-up efforts should go into this method. * * @author mike@givingassistant.org * @version 1.0 * * HISTORY: * ======== * 03-18-15 mks original coding * 05-11-16 mks ome-287: support for dynamic resource management * */ public function __destruct() { //do nothing } }