/* Copyright 2010 Aaron J. Radke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package cc.drx //Log Level/Logger type class trait LogLevel{ def log(kvs:List[(String,Any)], srcLoc:File.Loc):Unit = require(skip == false, "The Log macro should prevent this method from being called if the skip is set") private val nullFile = File.Loc(File("/dev/null"),0) def apply(kvs:Tuple2[Any,Any]*):Unit = { val kvStrings = kvs.toList.map{ case (Symbol(k),v) => k.underscore -> v case (k,v) => k.toString.underscore -> v } log(kvStrings, nullFile) //use the generic Log without a srcLoc } /**if this value is set then the macro should fire a skip for this event whenvernever even expand or evaluate the logging values */ def skip:Boolean = true } /**a selection of implicit log levels, these can be used with import LogLevel.Debug to set a scoped debug level */ object LogLevel { /**show timestamp, feature values, and line numbers*/ case object Debug extends LogLevel { override def skip = false override def log(kvs:List[(String,Any)], srcLoc:File.Loc):Unit = Console.println( Date.now.krypton.toString + " " + (kvs ++ List("line" -> srcLoc.line, "file" -> srcLoc.file.unixPath) ).map(Format.kvColor).mkString(" ") ) } /**just show feature values*/ case object Info extends LogLevel{ override def skip = false override def log(kvs:List[(String,Any)], srcLoc:File.Loc):Unit = Console.println( kvs.map(Format.kvColor).mkString(" ") ) } /**don't show anything*/ case object None extends LogLevel /**rate limited progress like info with ansi overwrite*/ case object Progress extends LogLevel{ //--constants val dt = 100.ms private val ticker = new Ticker(dt) override def skip = {ticker.tick; ticker.count != 0} override def log(kvs:List[(String,Any)], srcLoc:File.Loc):Unit = { val rateKvs = kvs :+ ("logRate" -> ticker.meanRate) Ansi.printtmp( rateKvs.map(Format.kvColor).mkString(" ") ) } } private class Ticker(dt:Time=100.ms){ //--constants val dtNanos = dt.ns.toLong //--mutables private var lastTickTime:Long = System.nanoTime var count:Long = 0L //number of skip tests per dt val rateStat:StatBuilder = new StatBuilder private def nanosSinceLast = (System.nanoTime - lastTickTime) def tick:Unit = { count += 1 val ns = nanosSinceLast if(ns >= dtNanos){ //--calculate tick rates val rate = count*1E9/ns rateStat += rate //--reset counters lastTickTime = System.nanoTime count = 0 } } def meanRate:Frequency = rateStat.mean.hz def lastRate:Frequency = rateStat.last.hz } /**rate limited progress like info with ansi overwrite*/ /* case object Top extends LogLevel{ private val di = collections.mutable.Map[File.Loc,Ticker].empty.withDefault(0L) //TODO use a hash to store separate log times keying off of srcLoc (file & name) //TODO use the set of of active logs for a `top` like dashboard override def skip = ??? override def log(kvs:List[(String,Any)], srcLoc:File.Loc):Unit = ??? } */ implicit val defaultDrxLogLevel:LogLevel = LogLevel.Debug }