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

com.twitter.finagle.netty3.ChannelSnooper.scala Maven / Gradle / Ivy

The newest version!
package com.twitter.finagle.netty3

import java.io.PrintStream
import java.nio.charset.Charset

import org.jboss.netty.channel._
import org.jboss.netty.buffer.ChannelBuffer

/** Log events on channels */
trait ChannelSnooper extends ChannelDownstreamHandler with ChannelUpstreamHandler {
  val name: String

  private[this] lazy val printStream = new PrintStream(System.out, true, "UTF-8")

  def printer(message: String, exc: Throwable = null) {
    printStream.println(message)
    if (exc != null) {
      exc.printStackTrace(printStream)
    }
  }

  def print(id: java.lang.Integer, indicator: String, message: String) {
    printer("%08x %6s %s %s".format(id, name, indicator, message))
  }

  val upIndicator = "^"
  val downIndicator = "v"

  def printUp(ch: Channel, message: String) = print(ch.getId, upIndicator, message)
  def printDown(ch: Channel, message: String) = print(ch.getId, downIndicator, message)
}

/** Log message events */
class ChannelBufferSnooper(val name: String) extends ChannelSnooper {
  // TODO: provide hexdump also. for now we deal only in ASCII
  // characters.

  override def handleUpstream(ctx: ChannelHandlerContext, e: ChannelEvent) {
    e match {
      case me: UpstreamMessageEvent if me.getMessage.isInstanceOf[ChannelBuffer] =>
        val buf = me.getMessage.asInstanceOf[ChannelBuffer]
        dump(printUp, ctx.getChannel, buf)
      case _ =>
        ()
    }

    ctx.sendUpstream(e)
  }

  override def handleDownstream(ctx: ChannelHandlerContext, e: ChannelEvent) {
    e match {
      case me: DownstreamMessageEvent if me.getMessage.isInstanceOf[ChannelBuffer] =>
        val buf = me.getMessage.asInstanceOf[ChannelBuffer]
        dump(printDown, ctx.getChannel, buf)
      case _ =>
        ()
    }

    ctx.sendDownstream(e)
  }

  def dump(printer: (Channel, String) => Unit, ch: Channel, buf: ChannelBuffer) {
    val rawStr = buf.toString(buf.readerIndex, buf.readableBytes, Charset.forName("UTF-8"))
    val str = rawStr.replaceAll("\r", "\\\\r").replaceAll("\n", "\\\\n")
    val asciiStr = str map { c =>
      if (c >= 32 && c < 128)
        c
      else
        '?'
    }

    for (i <- 0 until asciiStr.length by 60)
      printer(ch, asciiStr.slice(i, i + 60).lines.mkString("\\n"))
  }
}

/** Log raw channel events */
class SimpleChannelSnooper(val name: String) extends ChannelSnooper {
  override def handleUpstream(ctx: ChannelHandlerContext, e: ChannelEvent) {
    printUp(ctx.getChannel, e.toString)
    if (e.isInstanceOf[ExceptionEvent])
      printer("Snooped exception", e.asInstanceOf[ExceptionEvent].getCause)

    ctx.sendUpstream(e)
  }

  override def handleDownstream(ctx: ChannelHandlerContext, e: ChannelEvent) {
    printDown(ctx.getChannel, e.toString)
    ctx.sendDownstream(e)
  }
}

object ChannelSnooper {
  def apply(name: String)(thePrinter: (String, Throwable) => Unit) =
    new SimpleChannelSnooper(name) {
      override def printer(message: String, exc: Throwable = null) = thePrinter(message, exc)
    }

  def addLast(name: String, p: ChannelPipeline) =
    p.addLast("snooper-%s".format(name), new SimpleChannelSnooper(name))

  def addFirst(name: String, p: ChannelPipeline) =
    p.addFirst("snooper-%s".format(name), new SimpleChannelSnooper(name))
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy