I get the above message on the console at the start of program execution, and am unclear how to resolve it. For information, the program is written in Scala, uses the grizzled-slf4j adapter over slf4j with the logback provider, and has a logback.groovy file in the classpath. Here's the latter's contents:
import static ch.qos.logback.classic.Level.*
import ch.qos.logback.classic.encoder.*
import ch.qos.logback.classic.filter.*
import ch.qos.logback.core.*
import ch.qos.logback.core.status.OnConsoleStatusListener
statusListener(OnConsoleStatusListener)
appender("STDOUT", ConsoleAppender) {
filter(ThresholdFilter) {
level = INFO
}
encoder(PatternLayoutEncoder) {
pattern = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
}
}
root(INFO, ['WARN'])
Ideas welcome (the logging itself works fine, the issue is just the initial message).
Change
root(INFO, ['WARN'])
to
root(INFO, ['STDOUT'])
Related
I am coding an application with Akka v2.5.23. The application involves below actors:
An router actor class named CalculatorRouter
An routee actor class named Calculator
I've configured a PinnedDispatcher when creating Calculator actor and put log.info in this actor class's receive method. I've expected to see in the log file the thread name field to contain pinned. However, the thread name field is default-dispatcher. I've searched in the log file and found that all the thread name with respect to this log.info to be default-dispatcher. Is there something wrong with my code?
Log file snippet:
09:49:25.116 [server-akka.actor.default-dispatcher-14] INFO handler.Calculator $anonfun$applyOrElse$3 92 - akka://server/user/device/$a/$a Total calc received
Follows are the code snippets:
class CalculatorRouter extends Actor with ActorLogging {
var router = {
val routees = Vector.fill(5) {
val r = context.actorOf(Props[Calculator].withDispatcher("calc.my-pinned-dispatcher"))
context.watch(r)
ActorRefRoutee(r)
}
Router(SmallestMailboxRoutingLogic(), routees)
}
def receive = {
case w: Calc => router.route(w, sender)
case Terminated(a) =>
router.removeRoutee(a)
val r = context.actorOf(Props[Calculator].withDispatcher("calc.my-pinned-dispatcher"))
context.watch(r)
router = router.addRoutee(r)
}
}
The calc.my-pinned-dispatcher is configured as follows:
calc.my-pinned-dispatcher {
executor="thread-pool-executor"
type=PinnedDispatcher
}
Source code of class calculator as follows:
class Calculator extends Actor with ActorLogging {
val w = new UdanRemoteCalculateTotalBalanceTime
def receive = {
case TotalCalc(fn, ocvFilepath, ratedCapacity, battCount) ⇒
log.info(s"${self.path} Total calc received")
Try{
w.CalculateTotalBalanceTime(1, fn, ocvFilepath, ratedCapacity)
} match {
case Success(t) ⇒
val v = t.getIntData
sender.!(Calculated(v))(context.parent)
case Failure(e) ⇒ log.error(e.getMessage)
}
}
}
object Calculator {
sealed trait Calc
final case class TotalCalc(filename: String, ocvFilepath: String, ratedCapacity: String, batteryCount: Int) extends Calc
}
logback.xml
<configuration debug="true">
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<!-- reset all previous level configurations of all j.u.l. loggers -->
<resetJUL>true</resetJUL>
</contextListener>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/app.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>/var/log/app.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- keep 30 days' worth of history capped at 3GB total size -->
<maxHistory>100</maxHistory>
<totalSizeCap>30000MB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %M %L - %msg%n</pattern>
</encoder>
</appender>
<appender name="ASYNCFILE" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE" />
<queueSize>500</queueSize>
<includeCallerData>true</includeCallerData>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %M %L - %msg%n</pattern>
</encoder>
</appender>
<logger name="application" level="DEBUG"/>
<root level="INFo">
<appender-ref ref="ASYNCFILE"/>
</root>
</configuration>
'20 Mar 4 Update
Thanks #anand-sai. After I put akka.loggers-dispatcher = "calc.my-pinned-dispatcher" in conf file, I've got my-pinned-dispatcher-xx as the thread name in every line of the log file. I thought the thread name should indicate the thread wherein actor Calculator's receive method is executing, in this case, something similar to 'pinned-dispatcher-xx' as the thread was obtained by a pinned dispatcher per my configuration. Now it proves that it indicates the thread obtained by logger's dispatcher. If this is the case, how to log the thread name for an actor's message handler code?
I think the solution is to add akka.loggers-dispatcher in your application.conf
calc.my-pinned-dispatcher {
executor="thread-pool-executor"
type=PinnedDispatcher
}
akka.loggers-dispatcher = "calc.my-pinned-dispatcher"
If you search for logger-dispatcher in the default configuration of akka, you will find the value to be "akka.actor.default-dispatcher` and we need to override this config as shown above.
EDIT
ActorLogging is asynchronous. When you log using ActorLogging, it sends a message to the logging actor, which by default runs on the default dispatcher. Logback logs the thread that called it, which will be the ActorLogging actor's thread, not your actor's thread.In order to achieve this goal, there is a so-called Mapped Diagnostic Context (MDC) that captures the akka source(The path of the actor in which the logging was performed ) , source thread( the thread in which the logging was performed) and much more in which the logging was performed.
As given in the documentation:
Since the logging is done asynchronously the thread in which the
logging was performed is captured in MDC with attribute name
sourceThread.
The path of the actor in which the logging was performed is available
in the MDC with attribute name akkaSource.
The actor system name in which the logging was performed is available
in the MDC with attribute name sourceActorSystem, but that is
typically also included in the akkaSource attribute.
The address of the actor system, containing host and port if the
system is using cluster, is available through akkaAddress.
For typed actors the log event timestamp is taken when the log call
was made but for Akka’s internal logging as well as the classic actor
logging is asynchronous which means that the timestamp of a log entry
is taken from when the underlying logger implementation is called,
which can be surprising at first. If you want to more accurately
output the timestamp for such loggers, use the MDC attribute
akkaTimestamp. Note that the MDC key will not have any value for a
typed actor.
Let me know if it helps!!
I am using "LazyLogging" and configured the "logback" to print the class and line number of the print statement.
I want to create a small wrapper function in my code that prints some context along with the regular message. But since the actual "caller" of the log function is inside this new wrapper function, I am losing my class and line number of the true print statement.
For instance:
class Foo(context: Context) extends LazyLogging {
...
...
logger.info("some message") // assume this is line "41"
...
...
}
the resulting console log looks like:
14:40:39 INFO [Foo:41] some message
But lets say I create a small wrapper that should print the "context" with each log statement:
class Foo(context: Context) extends LazyLogging {
...
...
def logWithContext(msg: String) = logger.info(s"[$context] $msg") // assume this is line 5
...
...
logWithContext("some message") // assume this is line "41"
...
...
logWithContext("a different message") // assume this is line "51"
...
...
}
But now the resulting console always appears at line 5
14:40:39 INFO [Foo:5] some message
14:40:39 INFO [Foo:5] a different message
I'm guessing that I need to return an "unapplied" function to the caller and apply in their context (on their line), or some other sort of macro (such as ones I would have done in old school C/C++ etc. capturing the caller's context)
Might not be what you are looking for, but logback could potentially rescue you via the, somewaht unwieldy caller{depth}
I have defined the logback conf:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} %caller{4} - %msg %n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
and my code is:
import com.typesafe.scalalogging.LazyLogging
object Main extends App with LazyLogging {
def lg(msg: String) = logger.info("prefix + " + msg)
lg("1")
lg("2")
}
and the result is:
270 [main] INFO lg.Main$ Caller+0 at lg.Main$.lg(Main.scala:7)
Caller+1 at lg.Main$.delayedEndpoint$lg$Main$1(Main.scala:9)
Caller+2 at lg.Main$delayedInit$body.apply(Main.scala:5)
Caller+3 at scala.Function0.apply$mcV$sp(Function0.scala:34)
- prefix + 1
273 [main] INFO lg.Main$ Caller+0 at lg.Main$.lg(Main.scala:7)
Caller+1 at lg.Main$.delayedEndpoint$lg$Main$1(Main.scala:11)
Caller+2 at lg.Main$delayedInit$body.apply(Main.scala:5)
Caller+3 at scala.Function0.apply$mcV$sp(Function0.scala:34)
- prefix + 2
Main.scala:9 and Main.scala:11 differentiate the caller line
I am playing around with spray.io and I am not able to make spray debugging directives logRequestResponse work - I don't see any output in the log.
val route: Route = {
pathPrefix("city") {
pathPrefix("v1") {
path("transaction" / Segment / Segment) {
(siteId: String, transactionId: String) =>
post {
authenticate(BasicAuth(UserPasswordAuthenticator _, realm = "bd cinema import api")) {
user =>
DebuggingDirectives.logRequestResponse("city-trans", Logging.InfoLevel) {
val resp = "Hello"
complete {
resp
}
}
}
}
}
}
}
}
Am I missing something here?
Do I need to enable debugging in global somewhere in spray configuration? I tried different places and none of them worked as expected
Check you have sensible values at your application.conf and logback.xml as these sample files on the Spray project
Pay attention at application.conf akka.loglevel=INFO
akka {
log-config-on-start = on
loglevel = "INFO"
actor.timeoutsecs = 2
loggers = ["akka.event.slf4j.Slf4jLogger"]
}
A minimum logback.xml to display logs on stdout.
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<target>System.out</target>
<encoder>
<pattern>[%d{dd/MM/yyyy HH:mm:ss.SSS}] [%level] [%thread] %logger{36} - %msg %n</pattern>
<!--<pattern>%X{akkaTimestamp} %-5level[%thread] %logger{0} - %msg%n</pattern>-->
</encoder>
</appender>
<!-- <logger name="com.vegatic" level="DEBUG"/> -->
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
Usual suspects are logger's name attributes not matching the Scala namespaces or not verbose enough which have been commented on the example above for clarity
Docs link for LoggingContext
A LoggingAdapter that can always be supplied implicitly. If an
implicit ActorSystem the created LoggingContext forwards to the log of
the system. If an implicit ActorContext is in scope the created
LoggingContext uses the context's ActorRef as a log source. Otherwise,
i.e. if neither an ActorSystem nor an ActorContext is implicitly
available, the created LoggingContext will forward to NoLogging, i.e.
"/dev/null".
I am using Logback + SLF4J to do logging for those actors with trait of akka.actor.ActorLogging. However, when I do the code log.error("Error occur!", e), the stack trace of the exception e is not logged, but only print a line of Error occur! WARNING arguments left: 1. I wonder why and how to print the stack trace in the log file. Thank you. The following is my logback.groovy file configuration.
appender("FILE", RollingFileAppender) {
file = "./logs/logd.txt"
append = true
rollingPolicy(TimeBasedRollingPolicy) {
fileNamePattern = "./logs/logd.%d{yyyy-MM-dd}.log"
maxHistory = 30
}
encoder(PatternLayoutEncoder) {
pattern = "%date{ISO8601} [%thread] %-5level %logger{36} %X{sourceThread} - %msg%n"
}
}
root(DEBUG, ["FILE"])
Akka has separate logging, which is configured in Akka's application.conf. If you want bridge to SLF4J/Logback - use thеsе settings:
akka {
loggers = ["akka.event.slf4j.Slf4jLogger"]
loglevel = "DEBUG"
}
See: http://doc.akka.io/docs/akka/2.0/scala/logging.html
As far as I can see here, reason (Throwable) should be the first argument of log.error:
def error(cause: Throwable, message: String)
That's why you see "WARNING arguments left" - your Throwable argument was just ignored.
The 'cause' exception should be the first argument to error, not the second (as correctly mentioned by JasonG in a comment on another answer).
Using the Akka log system instead of 'bare' scala-logging has some advantages around automatically added metadata and easier testing/filtering.
See also:
http://doc.akka.io/docs/akka/2.4.16/scala/logging.html
http://doc.akka.io/api/akka/2.4/akka/event/LoggingAdapter.html#error(cause:Throwable,message:String):Unit
I have a (Smart)GWT application, that uses Spring on the server-side, and logs its stuff there via log4j. This works (deploying on tomcat6/ubuntu 10.04 LTS).
On the client-side I use the gwt-log remote logging library, configured properly. When running debug mode, I see the gwt-logs in the Eclipse 'Development Mode' pane. When deployed however, I don't see the gwt-log logs. I have configured things as follows:
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
...
<appender name="FILE_LOG2" class="org.apache.log4j.FileAppender">
<param name="File" value="${PuzzelVandaag-instance-root}WEB-INF/logs/Sytematic.log" />
<param name="Append" value="true" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="--- %d [%.4t] %-5p %c{1} - %m%n"/>
</layout>
</appender>
...
<!-- this one works, normal server-side code -->
<category name="com.isomorphic">
<priority value="DEBUG" />
<appender-ref ref="FILE_LOG2" />
</category>
<!-- currently I use this to configure gwt-log stuff. Is this the right way? -->
<category name="gwt-log">
<level value="DEBUG" />
<appender-ref ref="FILE_LOG2"/>
</category>
The server-side package logging works, but I have troubles with the client-side. I am fairly sure the remote logging servlet works, as I don't see any errors on this. I have it configured as follows, in web.xml:
<servlet>
<servlet-name>gwt-log-remote-logger-servlet</servlet-name>
<servlet-class>com.allen_sauer.gwt.log.server.RemoteLoggerServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>gwt-log-remote-logger-servlet</servlet-name>
<url-pattern>/[modulename]/gwt-log</url-pattern>
</servlet-mapping>
When I log stuff, I do a call like Log.debug("some msg"), whilst importing com.allen_sauer.gwt.log.client.Log.
All-in-all I think I followed the correct approach. I also run hosted mode with the -Dlog4j.debug parameter, and this is what it tells me:
log4j: Retreiving an instance of org.apache.log4j.Logger.
log4j: Setting [gwt-log] additivity to [true].
log4j: Level value for gwt-log is [DEBUG].
log4j: gwt-log level set to DEBUG
log4j: Adding appender named [STDOUT] to category [gwt-log].
log4j: Adding appender named [SmartClientLog] to category [gwt-log].
log4j: Adding appender named [FILE_LOG2] to category [gwt-log].
For completion, here is the relevant part of .gwt.xml:
<inherits name="com.allen_sauer.gwt.log.gwt-log-DEBUG"/>
<set-property name="log_DivLogger" value="DISABLED"/>
<!-- In gwt-log-3.0.3 or later -->
<inherits name="com.allen_sauer.gwt.log.gwt-log-RemoteLogger"/>
Am I missing something obvious? I am a log4j newbie... Any help would be greatly appreciated!
If you take a look at the com.google.gwt.logging.server.RemoteLoggingServiceImpl code you will see that it is using java.util.logging.Logger to perform it's logging.
You are using Log4j.
There are two options for getting your logs to appear in Log4j.
Implement your own RemoteLoggingService
Use slf4j to "bridge" java.util.logging with log4j logging
Option 1 is not too hard.
I have below the class I created for this. Remember to point your web.xml to this new class.
import java.util.logging.LogRecord;
import com.google.gwt.logging.shared.RemoteLoggingService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import java.util.logging.Level;
import org.springframework.stereotype.Component;
public class MyRemoteLoggingServlet extends RemoteServiceServlet implements RemoteLoggingService {
private final MyLogger logger = MyLoggerFactory.getLogger(getClass());
#Override
public String logOnServer(LogRecord record) {
Level level = record.getLevel();
String message = record.getMessage();
if (Level.INFO.equals(level)) {
logger.info(message);
} else if (Level.SEVERE.equals(level)) {
logger.error(message);
} else if (Level.WARNING.equals(level)) {
logger.warn(message);
} else if (Level.FINE.equals(level)) {
logger.debug(message);
}
return null;
}
}
Option 2
In this option you use SLF4J for your logging and configure a bridge that will redirect the java.util.logging.Logger to Log4j.
I havent implemented this method myself, but you can read about it here:
JUL to SLF4J Bridge
I took this approach, works for me.
public class UILogging extends RemoteServiceServlet implements
RemoteLoggingService {
private static final String SYMBOL_MAPS = "symbolMaps";
private static StackTraceDeobfuscator deobfuscator = null;
private static Logger logger = Logger.getLogger(UILogging.class);
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
setSymbolMapsDirectory(config.getInitParameter(SYMBOL_MAPS));
}
/**
* Logs a Log Record which has been serialized using GWT RPC on the server.
*
* #return either an error message, or null if logging is successful.
*/
public final String logOnServer(LogRecord lr) {
String strongName = getPermutationStrongName();
try {
if (deobfuscator != null) {
lr = deobfuscator.deobfuscateLogRecord(lr, strongName);
}
if (lr.getLevel().equals(Level.SEVERE)) {
logger.error(lr.getMessage(),lr.getThrown());
} else if (lr.getLevel().equals(Level.INFO)) {
logger.info(lr.getMessage(),lr.getThrown());
} else if (lr.getLevel().equals(Level.WARNING)) {
logger.warn(lr.getMessage(),lr.getThrown());
} else if (lr.getLevel().equals(Level.FINE)) {
logger.debug(lr.getMessage(),lr.getThrown());
} else if (lr.getLevel().equals(Level.ALL)) {
logger.trace(lr.getMessage(),lr.getThrown());
}
} catch (Exception e) {
logger.error("Remote logging failed", e);
return "Remote logging failed, check stack trace for details.";
}
return null;
}
/**
* By default, this service does not do any deobfuscation. In order to do
* server side deobfuscation, you must copy the symbolMaps files to a
* directory visible to the server and set the directory using this method.
*
* #param symbolMapsDir
*/
public void setSymbolMapsDirectory(String symbolMapsDir) {
if (deobfuscator == null) {
deobfuscator = new StackTraceDeobfuscator(symbolMapsDir);
} else {
deobfuscator.setSymbolMapsDirectory(symbolMapsDir);
}
}
}