Files
namaste/classes/gacLogClient.class.inc
gramps 373ebc8c93 Archive: Namaste PHP AMQP framework v1.0 (2017-2020)
952 days continuous production uptime, 40k+ tp/s single node.
Original corpo Bitbucket history not included — clean archive commit.
2026-04-05 09:49:30 -07:00

173 lines
7.4 KiB
PHP

<?php
/**
* gacLogClient -- class definition
*
* this is the class for declaring a logClient for use in testing, or within the framework when we need to publish
* a log event to another queue.
*
* This class simply abstracts the RabbitMQ processes so that you don't have to re-write all the RMQ code every
* time you want to publish a message to the log exchange.
*
* IMPORTANT NOTE:
* ---------------
* Whenever you add a qualifying queue to the pantheon, you'll need to update the constructor class, adding the queue
* name to the $validQueues member, and to the switch-case statement that assigns the correct environment.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* ========
* 09-18-19 mks DB-136: original coding
* 12-04-19 mks DB-140: PHP 7.4 compliance
* 01-07-20 mks DB-150: PHP 7.4 member variable casting
*
*/
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Exception\AMQPRuntimeException;
use PhpAmqpLib\Exception\AMQPTimeoutException;
use PhpAmqpLib\Message\AMQPMessage;
class gacLogClient {
private ?object $rabbitConnection;
private AMQPChannel $rabbitChannel;
private string $res = 'BRCL: ';
// if you add to the log-exchange bindings, for either service or source, remember to update these arrays as needed
private array $validTypes = [ EXCHANGE_SOURCE_LOGS, EXCHANGE_SOURCE_METRICS, STAR ];
public string $status;
/**
* __construct() -- public method
*
* the constructor instantiates the class and establishes a connection to the RMQ Log Exchange.
*
* other client classes, such as BrokerClient, require a queue name to be passed to the constructor because these
* clients are connecting directly to the queues to publish an event. This client, instead, connects to the
* log exchange (instead of a queue) and publishes to the exchange.
*
* Within the bindings for the exchange which are coded in the brokers for each of the exchange queues, are the
* configuration directives for how messages are routed by the exchange to the destination queues. Messages
* published to the exchange can be routed to one, several, or all of the queues bound to the exchange.
*
* That is why there isn't a string parameter passed to this class' constructor - because this client connects
* to the exchange and not to a broker specified by the input parameter.
*
* method returns an implicit boolean via a class member (status) indicating whether or not the resource management
* was successful and attempts to provide diagnostics via logging, cli output, or via the status member variable.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
*
* HISTORY:
* ========
* 09-18-19 mks DB-136: original coding
*
*/
public function __construct()
{
register_shutdown_function(array($this, '__destruct'));
$this->status = false;
try {
// fetch the AMQPStreamConnection to the Admin service
$this->rabbitConnection = gasResourceManager::fetchResource(RESOURCE_ADMIN);
if (is_null($this->rabbitConnection)) {
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
consoleLog($this->res, CON_ERROR, $hdr . ERROR_RESOURCE_404 . RESOURCE_ADMIN);
return;
}
$this->rabbitChannel = $this->rabbitConnection->channel();
// connect the channel to the logging exchange
$this->rabbitChannel->exchange_declare(EXCHANGE_NAME_TOPIC_LOGS, EXCHANGE_TYPE_TOPIC, false, false, false);
$this->status = true;
} catch (AMQPRuntimeException | AMQPTimeoutException | Throwable $t) {
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
consoleLog($this->res, CON_ERROR, $hdr . ERROR_THROWABLE_EXCEPTION);
consoleLog($this->res, CON_ERROR, $hdr . $t->getMessage());
}
return;
}
/**
* call() -- public method
*
* This method is invoked outside of the class and is the entry point for publishing a message request to the
* logging exchange. It creates a new AMQP message and publishes it to the exchange, defined in the constructor),
* and then blocks-and-waits for a response from the remote (vault) service.
*
* There are two input parameters to this method:
*
* $_data -- this is the payload data that, untouched, is converted into an AMQPMessage class object
* $_route -- this defines how the exchange will handle the incoming message (<service>.<source> format)
*
* For exchange routing, the $_route is required and critical for delivering a successful message request to
* the logging exchange. The following values are valid routes with the default route set to STAR:
*
* EXCHANGE_SOURCE_METRICS, EXCHANGE_SOURCE_LOGS, STAR
*
* Publishing a message is exception trapped and will generate a log message at the warn level if tripped.
*
* The method returns a boolean to the calling client if the message was successfully published to the exchange.
* Since logging is fire-n-forget, we can't know if the message was accepted... if a false value is returned,
* then the client should check the console log as their request failed routing validation.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* @param $_data -- the payload to be converted to an AMQPMessage class object
* @param $_route -- The declared route for the message request ( defaults to: * )
*
* @return bool -- indicates if the message was successfully published or not
*
*
* HISTORY:
* ========
* 09-18-19 mks DB-136: original coding
*
*/
public function call(string $_data, string $_route = STAR): bool
{
// validate the routing string for the exchange...
if (!in_array($_route, $this->validTypes)) {
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
$msg = sprintf(ERROR_SERVICE_SOURCE_UNK, $_route);
consoleLog($this->res, CON_ERROR, $hdr . $msg);
return false;
}
// create and publish the message to the logging exchange
try {
$rabbitMessage = new AMQPMessage((string)$_data);
$this->rabbitChannel->basic_publish($rabbitMessage, EXCHANGE_NAME_TOPIC_LOGS, $_route);
consoleLog($this->res, CON_SUCCESS, SUCCESS_PUBLISHED . $_route);
} catch (AMQPTimeoutException | AMQPRuntimeException | Throwable $e) {
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
consoleLog($this->res, CON_ERROR, $hdr . $e->getMessage());
}
return true;
}
public function __destruct()
{
// As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
//
// destructor is registered shut-down function in constructor -- so any recovery
// efforts should go in this method.
try {
$this->rabbitChannel->close();
$this->rabbitConnection->close();
} catch (AMQPTimeoutException | AMQPRuntimeException | Throwable $t) {
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
consoleLog($this->res, CON_ERROR, $hdr . ERROR_THROWABLE_EXCEPTION);
consoleLog($this->res, CON_ERROR, $hdr . $t->getMessage());
}
}
}