All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.itv.bucky.LoggingAmqpClient.scala Maven / Gradle / Ivy

package com.itv.bucky

import cats.effect.{ConcurrentEffect, Resource}
import com.typesafe.scalalogging.StrictLogging
import cats._
import cats.implicits._
import java.nio.charset.Charset

import com.itv.bucky.consume._
import com.itv.bucky.publish._
import scala.concurrent.duration._
import scala.concurrent.duration.FiniteDuration
import scala.language.higherKinds

object LoggingAmqpClient extends StrictLogging {

  private[bucky] def logSuccessfullPublishMessage[F[_]](charset: Charset, cmd: PublishCommand)(implicit F: ConcurrentEffect[F]): F[Unit] =
    F.delay(
      logger.info("Successfully published message with rk:'{}', exchange:{} and message:'{}'",
                  cmd.routingKey.value,
                  cmd.exchange.value,
                  new String(cmd.body.value, charset))
    )

  private[bucky] def logFailedPublishMessage[F[_]](t: Throwable, charset: Charset, cmd: PublishCommand)(implicit F: ConcurrentEffect[F]): F[Unit] =
    F.delay(
      logger.error("Failed to publish message with rk:'{}', exchange:'{}' and message:'{}'",
                   cmd.routingKey.value,
                   cmd.exchange.value,
                   new String(cmd.body.value, charset),
                   t)
    )

  private[bucky] def logFailedHandler[F[_]](charset: Charset,
                                            queueName: QueueName,
                                            exceptionalAction: ConsumeAction,
                                            delivery: Delivery,
                                            t: Throwable)(implicit F: ConcurrentEffect[F]): F[Unit] = F.delay {
    logger.error(
      s"Failed to execute handler for message with rk '{}' on queue '{}' and exchange '{}'. Will return '{}'. message: '{}', headers:'{}'",
      delivery.envelope.routingKey.value,
      queueName.value,
      delivery.envelope.exchangeName,
      exceptionalAction,
      new String(delivery.body.value, charset),
      delivery.properties.headers,
      t
    )
  }

  private[bucky] def logSuccessfulHandler[F[_]](charset: Charset, queueName: QueueName, delivery: Delivery, ca: ConsumeAction)(
      implicit F: ConcurrentEffect[F]): F[Unit] = F.delay {
    logger.info(
      "Executed handler for message with rk:'{}' on queue:'{}' and exchange '{}'. Will return '{}'. message: '{}'",
      delivery.envelope.routingKey.value,
      queueName.value,
      delivery.envelope.exchangeName,
      ca.toString.toLowerCase,
      new String(delivery.body.value, charset)
    )
  }

  def apply[F[_]](amqpClient: AmqpClient[F], charset: Charset)(implicit F: ConcurrentEffect[F]): AmqpClient[F] =
    new AmqpClient[F] {
      override def declare(declarations: decl.Declaration*): F[Unit]          = amqpClient.declare(declarations)
      override def declare(declarations: Iterable[decl.Declaration]): F[Unit] = amqpClient.declare(declarations)

      override def publisher(): Publisher[F, PublishCommand] = {
        val originalPublisher = amqpClient.publisher()
        cmd: PublishCommand =>
          {
            (for {
              result <- originalPublisher(cmd).attempt
              _      <- result.fold[F[Unit]](logFailedPublishMessage(_, charset, cmd), _ => logSuccessfullPublishMessage(charset, cmd))
            } yield result).rethrow
          }
      }

      override def registerConsumer(queueName: QueueName,
                                    handler: Handler[F, Delivery],
                                    exceptionalAction: ConsumeAction,
                                    prefetchCount: Int,
                                    shutdownTimeout: FiniteDuration = 1.minutes,
                                    shutdownRetry: FiniteDuration = 500.millis): Resource[F, Unit] = {
        val newHandler = (delivery: Delivery) => {
          (for {
            result <- handler(delivery).attempt
            _ <- result.fold(logFailedHandler(charset, queueName, exceptionalAction, delivery, _),
                             logSuccessfulHandler(charset, queueName, delivery, _))
          } yield result).rethrow
        }
        amqpClient.registerConsumer(queueName, newHandler, exceptionalAction, prefetchCount)
      }

      override def isConnectionOpen: F[Boolean] = amqpClient.isConnectionOpen
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy