All Projects → tersesystems → blindsight

tersesystems / blindsight

Licence: other
Blindsight is a Scala logging API with DSL based structured logging, fluent logging, semantic logging, flow logging, and context aware logging.

Programming Languages

scala
5932 projects

Projects that are alternatives of or similar to blindsight

Zio Logging
Simple logging for ZIO apps, with correlation, context & pluggable backends out of the box.
Stars: ✭ 85 (+21.43%)
Mutual labels:  slf4j, tracing
echopraxia
Java Logging API with clean and simple structured logging and conditional & contextual features. JSON implementations in Logback and Log4J.
Stars: ✭ 37 (-47.14%)
Mutual labels:  slf4j, structured-logging
Terse Logback
Structured Logging, Tracing, and Observability with Logback
Stars: ✭ 146 (+108.57%)
Mutual labels:  slf4j, structured-logging
Izumi
Productivity-oriented collection of lightweight fancy stuff for Scala toolchain
Stars: ✭ 423 (+504.29%)
Mutual labels:  slf4j, structured-logging
BOBBIN
Revolutionary high-performance Groovy/Java Slf4j logger
Stars: ✭ 17 (-75.71%)
Mutual labels:  slf4j, slf4j-api
cosmos-logging
Logging component for .NET Core with nice APIs for developers to use.
Stars: ✭ 28 (-60%)
Mutual labels:  structured-logging
ghostwriter
Solutions for instrumenting application flow tracking API calls into an existing code base in a non-invasive way
Stars: ✭ 17 (-75.71%)
Mutual labels:  tracing
zipkin-ruby-opentracing
OpenTracing Tracer implementation for Zipkin in Ruby
Stars: ✭ 15 (-78.57%)
Mutual labels:  tracing
easeagent
An agent component for the Java system
Stars: ✭ 437 (+524.29%)
Mutual labels:  tracing
gcloud-opentracing
OpenTracing Tracer implementation for GCloud StackDriver in Go.
Stars: ✭ 44 (-37.14%)
Mutual labels:  tracing
awesome-beam-monitoring
Curated list of awesome BEAM monitoring libraries and resources
Stars: ✭ 57 (-18.57%)
Mutual labels:  tracing
maple
Type-safe, consistently named and formatted, structured logging wrapper for SLF4J that's ideally suited for your logging aggregator.
Stars: ✭ 39 (-44.29%)
Mutual labels:  slf4j
iopipe-go
Go agent for AWS Lambda metrics, tracing, profiling & analytics
Stars: ✭ 18 (-74.29%)
Mutual labels:  tracing
uprobe-http-tracer
uprobe-based HTTP tracer for Go binaries
Stars: ✭ 45 (-35.71%)
Mutual labels:  tracing
structlog.nvim
Structured Logging for nvim, using Lua
Stars: ✭ 33 (-52.86%)
Mutual labels:  structured-logging
serverless-plugin-epsagon
Epsagon's plugin for Serverless Framework ⚡️
Stars: ✭ 53 (-24.29%)
Mutual labels:  tracing
money
Dapper Style Distributed Tracing Instrumentation Libraries
Stars: ✭ 65 (-7.14%)
Mutual labels:  tracing
ruby-sensor
💎 Ruby Distributed Tracing & Metrics Sensor for Instana
Stars: ✭ 23 (-67.14%)
Mutual labels:  tracing
quacktors
The quacking awesome Go actor model framework!
Stars: ✭ 14 (-80%)
Mutual labels:  tracing
timber-js
🌲 Great Node/JS logging made easy
Stars: ✭ 43 (-38.57%)
Mutual labels:  structured-logging

Blindsight

Maven central License Apache-2.0

Build Scala Steward badge

Suffering in silence, you check the logs for fresh telemetry.

You think: That can't be right.

-- Blindsight, Peter Watts

Blindsight is "observability through logging" where observability is defined as baked in high cardinality structured data with field types. The name is taken from Peter Watts' excellent first contact novel, Blindsight.

Blindsight is a logging library written in Scala that wraps SLF4J to add useful features that solve several outstanding problems with logging:

See the documentation for more details.

Example

You can check out a "starter project" at https://github.com/tersesystems/blindsight-starter.

There's an example application at https://github.com/tersesystems/play-blindsight that integrates with Honeycomb Tracing using the flow logger:

trace.png

Dependencies

The only hard dependency is the SLF4J API, but the DSL functionality is only implemented for Logback with logstash-logback-encoder.

Blindsight is a pure SLF4J wrapper: it delegates all logging through to the SLF4J API and does not configure or manage the SLF4J implementation at all.

Versions are published for Scala 2.11, 2.12, 2.13, and 3.0.0.

Install

See Setup for how to install Blindsight.

You can check out a "starter project" at https://github.com/tersesystems/blindsight-starter.

Because Blindsight uses a very recent version of Logstash that depends on Jackson 2.11.0, you may need to update your dependencies for the jackson-scala-module if you're using Play or Akka.

libraryDependencies += "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.11.0"

Usage

The easiest way to use Blindsight is to import the base package and the DSL:

import com.tersesystems.blindsight._
import com.tersesystems.blindsight.DSL._

To use a Blindsight Logger:

val logger = LoggerFactory.getLogger
logger.info("I am an SLF4J-like logger")

or in block form for diagnostic logging:

logger.debug { debug => debug("I am an SLF4J-like logger") }

Structured DSL:

import com.tersesystems.blindsight._
import com.tersesystems.blindsight.DSL._

logger.info("Logs with argument {}", bobj("array" -> Seq("one", "two", "three")))

Statement Interpolation:

val dayOfWeek = "Monday"
val temp = 72 

// macro expands this to:
// Statement("It is {} and the temperature is {} degrees.", Arguments(dayOfWeek, temp))
val statement: Statement = st"It is ${dayOfWeek} and the temperature is ${temp} degrees."

logger.info(statement)

Marker/Argument Type Classes:

case class Lotto(
  id: Long,
  winningNumbers: List[Int],
  winners: List[Winner],
  drawDate: Option[java.util.Date]
) {
  lazy val asBObject: BObject = "lotto" ->
      ("lotto-id"          -> id) ~
        ("winning-numbers" -> winningNumbers) ~
        ("draw-date"       -> drawDate.map(_.toString)) ~
        ("winners"         -> winners.map(w => w.asBObject))
}

object Lotto {
  implicit val toArgument: ToArgument[Lotto] = ToArgument { lotto => Argument(lotto.asBObject) }
}

val winners =
  List(Winner(23, List(2, 45, 34, 23, 3, 5)), Winner(54, List(52, 3, 12, 11, 18, 22)))
val lotto = Lotto(5, List(2, 45, 34, 23, 7, 5, 3), winners, None)

logger.info("message {}", lotto) // auto-converted to structured output

JSON-LD:

implicit val nodeObjectToArgument: ToArgument[NodeObject] = ToArgument[NodeObject] { nodeObject =>
  Argument(BlindsightASTMapping.toBObject(nodeObject))
}

implicit val nodeObjectToMarkers: ToMarkers[NodeObject] = ToMarkers { nodeObject =>
  Markers(BlindsightASTMapping.toBObject(nodeObject))
}

implicit val nodeObjectToStatement: ToStatement[NodeObject] = ...

class Foo extends LDContext { // LDContext contains all the type safe bindings
  def sayHello(): Unit = {
    val willPerson = NodeObject(
      `@type`    -> "Person",
      `@id`      -> willId,
      givenName  -> "Will",
      familyName -> "Sargent",
      parent     -> parentId,
      occupation -> Occupation(
        estimatedSalary = MonetaryAmount(Currency.getInstance("USD"), 1),
        name = "Code Monkey"
      )
    )

    logger.info("as an argument {}", willPerson) // as an argument
    logger.info(Markers(willPerson), "as a marker") // as a marker
    
    logger.semantic[NodeObject].info(willPerson) // or as a statement
  }
}

Fluent logging:

logger.fluent.info
  .message("The Magic Words are")
  .argument(Arguments("Squeamish", "Ossifrage"))
  .logWithPlaceholders()

Semantic logging:

// log only user events
logger.semantic[UserEvent].info(userEvent)

// Works well with refinement types
import eu.timepit.refined.api.Refined
import eu.timepit.refined.string._
import eu.timepit.refined._
logger.semantic[String Refined Url].info(refineMV(Url)("https://tersesystems.com"))

Flow logging:

import com.tersesystems.blindsight.flow._

implicit def flowBehavior[B]: FlowBehavior[B] = new SimpleFlowBehavior

val arg1: Int = 1
val arg2: Int = 2
val result:Int = logger.flow.trace(arg1 + arg2)

Conditional logging:

logger.withCondition(booleanCondition).info("Only logs when condition is true")

logger.info.when(booleanCondition) { info => info("when true") }

Context aware logging:

import DSL._

// Add key/value pairs with DSL and return a logger
val markerLogger = logger.withMarker(bobj("userId" -> userId))

// log with generated logger
markerLogger.info("Logging with user id added as a context marker!")

// can retrieve state markers
val contextMarkers: Markers = markerLogger.markers

Entry Transformation:

val logger = LoggerFactory.getLogger
               .withEntryTransform(e => e.copy(message = e.message + " IN BED"))

logger.info("You will discover your hidden talents")

Event Buffer:

val queueBuffer = EventBuffer(1)
val logger      = LoggerFactory.getLogger.withEventBuffer(queueBuffer)

logger.info("Hello world")

val event = queueBuffer.head

Scripting:

val scriptHandle = new ScriptHandle {
  override def isInvalid: Boolean = false // on file modification, etc
  override val script: String =
    """import strings as s from 'std.tf';
      |alias s.ends_with? as ends_with?;
      |
      |library blindsight {
      |  function evaluate: (long level, string enc, long line, string file) ->
      |    if (ends_with?(enc, "specialMethodName")) then true
      |    else false;
      |}
      |""".stripMargin
  override def report(e: Throwable): Unit = e.printStackTrace()
}
val scriptManager = new ScriptManager(scriptHandle) 
val location = new ScriptAwareLocation(scriptManager)

def specialMethodName = {
  // inside the specialMethodName method here :-)
  logger.debug.when(location.here) { log => 
    log("script allows selective logging by method or by line")
  }
}

Inspections:

import com.tersesystems.blindsight.inspection.InspectionMacros._

decorateIfs(dif => logger.debug(s"${dif.code} = ${dif.result}")) {
  if (System.currentTimeMillis() % 17 == 0) {
    println("branch 1")
  } else if (System.getProperty("derp") == null) {
    println("branch 2")
  } else {
    println("else branch")
  }
}

Benchmarks

Benchmarks are available here.

License

Blindsight is released under the "Apache 2" license. See LICENSE for specifics and copyright declaration.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].