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

io.policarp.logback.SplunkHecAppender.scala Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version
package io.policarp.logback

import java.util.concurrent.LinkedBlockingQueue

import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.core.AppenderBase
import io.policarp.logback.hec.SplunkHecClient
import io.policarp.logback.hec.skinnyhttp.{ SkinnyHecClient, SkinnyHttpLogFilter }
import monix.eval.Task
import monix.execution.Scheduler
import monix.reactive.{ Consumer, Observable }
import org.reactivestreams.{ Publisher, Subscriber, Subscription }

import scala.beans.BeanProperty
import scala.concurrent.duration._

class SplunkHecAppender extends SplunkHecAppenderBase with SkinnyHecClient {
  this.addFilter(new SkinnyHttpLogFilter())
}

trait SplunkHecAppenderBase extends AppenderBase[ILoggingEvent] {
  self: SplunkHecClient =>

  @BeanProperty var queue: Int = 1000
  @BeanProperty var buffer: Int = 25
  @BeanProperty var flush: Int = 30
  @BeanProperty var parallelism: Int = Runtime.getRuntime.availableProcessors()
  @BeanProperty var layout: SplunkHecJsonLayoutBase = SplunkHecJsonLayout()
  @BeanProperty var appenderStrategy: SplunkHecAppenderStrategy = BlockingSplunkHecAppenderStrategy()

  private implicit val scheduler = Scheduler.computation(parallelism)

  private implicit lazy val logPublisher = new LogPublisher(queue)
  private lazy val logStream = Observable.fromReactivePublisher(logPublisher).bufferTimedAndCounted(flush seconds, buffer)
  private lazy val logConsumer = Consumer.foreachParallelAsync[Task[Unit]](parallelism)(task => task)

  override def start() = {
    super.start()
    implicit val impliedLayout = layout
    logStream.map(postTask).runWith(logConsumer).runAsync
  }

  override def append(event: ILoggingEvent) = appenderStrategy.append(event)
}

private[logback] class LogPublisher(queueSize: Int)(implicit scheduler: Scheduler) extends Publisher[ILoggingEvent] {

  val logQueue = new LinkedBlockingQueue[ILoggingEvent](queueSize)

  def enqueue(event: ILoggingEvent) = logQueue.put(event)

  override def subscribe(subscriber: Subscriber[_ >: ILoggingEvent]) = {
    subscriber.onSubscribe(new Subscription {

      @volatile var cancelled = false

      override def cancel() = { cancelled = true }

      override def request(n: Long) = if (!cancelled) {
        Task {
          for (i <- 1L to n) {
            subscriber.onNext(logQueue.take())
          }
        }.runAsync
      }
    })
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy