Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

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

License

NotificationsYou must be signed in to change notification settings

tersesystems/blindsight

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Maven centralLicense Apache-2.0

BuildScala Steward badge

Blindsight is a logging library written in Scala that wraps SLF4J. The name is taken from Peter Watts' excellent first contact novel,Blindsight.

The core feature of Blindsight is that it is "type safe" -- rather than passing in arguments of typejava.lang.Object, the API accepts only objects that can be converted into anArgument through theToArgumenttype class.

val str: String = "string arg"val number: Int = 1val arg: Person = Person(name, age) // has a ToArgument[Person] type class instancelogger.info("{} {} {}", bool, number, person) // compiles finelogger.info("{}", new Object()) // WILL NOT COMPILE

By adding type safety, Blindsight gives the application more control over how data is logged, rather than implicitly relying on thetoString method to render data for logging purposes.

Blindsight addsuseful features that solve several outstanding problems with logging:

  • Rendering structured logs in multiple formats through an AST, along with an optional format-independentDSL.
  • Providing thread-safe context to logs throughcontext aware logging.
  • Time-based and targeted logging throughconditional logging.
  • Dynamic targeted logging throughscripting.
  • Easier "printf debugging" through macro basedinspections.

Using Scala to break apart the SLF4J API also makes constructing new logging APIs much easier. You have the option of creating your own, depending on your use case:

  • Building up complex logging statements throughfluent logging.
  • Enforcing user supplied type constraints throughsemantic logging.
  • Minimal-overhead tracing and causality tracking throughflow logging.
  • Managing complex relationships and schema throughJSON-LD.

Finally, there's also more advanced functionality to transform arguments and statements before entering SLF4J:

Seethe documentation for more details.

Blindsight and Echopraxia

If you are looking for a strict structured logging solution in Scala, please checkoutechopraxia-plusscala.

Structured logging is optional in Blindsight, and it's possible to mix structured and "flat" arguments and markers into a logging statement. In contrast,echopraxia-plusscalarequires structured logging and does not allow unstructured data as input.

Example

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

There's an example application athttps://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. Structured logging is implemented for Logback withlogstash-logback-encoder, but this is only a requirement if you are using structured logging.

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

SeeSetup for how to install Blindsight.

You can check out a "starter project" athttps://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 thejackson-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:

importcom.tersesystems.blindsight._importcom.tersesystems.blindsight.DSL._

To use a Blindsight Logger:

vallogger=LoggerFactory.getLoggerlogger.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:

importcom.tersesystems.blindsight._importcom.tersesystems.blindsight.DSL._logger.info("Logs with argument {}", bobj("array"->Seq("one","two","three")))

Statement Interpolation:

valdayOfWeek="Monday"valtemp=72// macro expands this to:// Statement("It is {} and the temperature is {} degrees.", Arguments(dayOfWeek, temp))valstatement:Statement=st"It is${dayOfWeek} and the temperature is${temp} degrees."logger.info(statement)

Marker/Argument Type Classes:

caseclassLotto(id:Long,winningNumbers:List[Int],winners:List[Winner],drawDate:Option[java.util.Date]) {lazyvalasBObject:BObject="lotto"->      ("lotto-id"-> id)~        ("winning-numbers"-> winningNumbers)~        ("draw-date"-> drawDate.map(_.toString))~        ("winners"-> winners.map(w=> w.asBObject))}objectLotto {implicitvaltoArgument:ToArgument[Lotto]=ToArgument { lotto=>Argument(lotto.asBObject) }}valwinners=List(Winner(23,List(2,45,34,23,3,5)),Winner(54,List(52,3,12,11,18,22)))vallotto=Lotto(5,List(2,45,34,23,7,5,3), winners,None)logger.info("message {}", lotto)// auto-converted to structured output

JSON-LD:

implicitvalnodeObjectToArgument:ToArgument[NodeObject]=ToArgument[NodeObject] { nodeObject=>Argument(BlindsightASTMapping.toBObject(nodeObject))}implicitvalnodeObjectToMarkers:ToMarkers[NodeObject]=ToMarkers { nodeObject=>Markers(BlindsightASTMapping.toBObject(nodeObject))}implicitvalnodeObjectToStatement:ToStatement[NodeObject]= ...classFooextendsLDContext {// LDContext contains all the type safe bindingsdefsayHello():Unit= {valwillPerson=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 eventslogger.semantic[UserEvent].info(userEvent)// Works well with refinement typesimporteu.timepit.refined.api.Refinedimporteu.timepit.refined.string._importeu.timepit.refined._logger.semantic[StringRefinedUrl].info(refineMV(Url)("https://tersesystems.com"))

Flow logging:

importcom.tersesystems.blindsight.flow._implicitdefflowBehavior[B]:FlowBehavior[B]=newSimpleFlowBehaviorvalarg1:Int=1valarg2:Int=2valresult: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:

importDSL._// Add key/value pairs with DSL and return a loggervalmarkerLogger= logger.withMarker(bobj("userId"-> userId))// log with generated loggermarkerLogger.info("Logging with user id added as a context marker!")// can retrieve state markersvalcontextMarkers:Markers= markerLogger.markers

Entry Transformation:

vallogger=LoggerFactory.getLogger               .withEntryTransform(e=> e.copy(message= e.message+" IN BED"))logger.info("You will discover your hidden talents")

Event Buffer:

valqueueBuffer=EventBuffer(1)vallogger=LoggerFactory.getLogger.withEventBuffer(queueBuffer)logger.info("Hello world")valevent= queueBuffer.head

Scripting:

valscriptHandle=newScriptHandle {overridedefisInvalid:Boolean=false// on file modification, etcoverridevalscript: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;      |}      |""".stripMarginoverridedefreport(e:Throwable):Unit= e.printStackTrace()}valscriptManager=newScriptManager(scriptHandle)vallocation=newScriptAwareLocation(scriptManager)defspecialMethodName= {// inside the specialMethodName method here :-)  logger.debug.when(location.here) { log=>     log("script allows selective logging by method or by line")  }}

Inspections:

importcom.tersesystems.blindsight.inspection.InspectionMacros._decorateIfs(dif=> logger.debug(s"${dif.code} =${dif.result}")) {if (System.currentTimeMillis()%17==0) {    println("branch 1")  }elseif (System.getProperty("derp")==null) {    println("branch 2")  }else {    println("else branch")  }}

Benchmarks

Benchmarks are availablehere.

License

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

About

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

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages


[8]ページ先頭

©2009-2025 Movatter.jp