Reputation: 1833
I'm trying to setup logentries on App Engine backend Java on Android Studio
I keep getting this error message whatever I did
log4j:WARN No appenders could be found for logger (root).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Here's my file structure
log4j.properties
log4j.rootLogger=ALL,le
log4j.appender.le=com.logentries.log4j.LogentriesAppender
log4j.appender.le.layout=org.apache.log4j.PatternLayout
log4j.appender.le.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss ZZZ} %-5p: %F:%L %m
log4j.appender.le.Token=HIDDEN
log4j.appender.le.Debug=True
log4j.appender.le.Ssl=False
log4j.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd" >
<log4j:configuration debug="true">
<appender name="le" class="com.logentries.log4j.LogentriesAppender">
<param name="Token" value="HIDDEN"/>
<param name="Ssl" value="false"/>
<param name="Debug" value="true"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{EEE MMM dd HH:mm:ss ZZZ yyyy}, (%F:%L) %-5p: %m"/>
</layout>
</appender>
<logger name="example">
<level value="debug"/>
</logger>
<root>
<priority value="debug"></priority>
<appender-ref ref="le"/>
</root>
</log4j:configuration>
appengine-web.xml
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>HIDDEN/application>
<version>1</version>
<threadsafe>true</threadsafe>
<system-properties>
<property name="java.util.logging.config.file" value="WEB-INF/classes/log4j.properties"/>
<property name="log4j.configuration" value="WEB-INF/classes/log4j.properties"/>
<property name="gcm.api.key" value="HIDDEN"/>
</system-properties>
</appengine-web-app>
Update
I found a very helpful tip in this question Where to place log4j.xml, basically put -Dlog4j.debug in the Java VM arguments and run App Engine in debug mode. It told me exactly whether it found log4j.xml or not. After much trial and error, It found it when I put it under WEB-INF/classes, now I can see precisely the full stack trace of the error I am having
INFO: Dev App Server is now running
log4j: Trying to find [log4j.xml] using context classloader com.google.appengine.tools.development.IsolatedAppClassLoader@560cbf1a.
log4j: Using URL [file:/C:/_Folder/_Code/AppNameHidden/backend/build/exploded-app/WEB-INF/classes/log4j.xml] for automatic log4j configuration.
log4j: Preferred configurator class: org.apache.log4j.xml.DOMConfigurator
log4j: System property is :null
log4j: Standard DocumentBuilderFactory search succeded.
log4j: DocumentBuilderFactory is: com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
log4j: debug attribute= "true".
log4j: reset attribute= "false".
log4j: Threshold ="null".
log4j: Retreiving an instance of org.apache.log4j.Logger.
log4j: Setting [example] additivity to [true].
log4j: Level value for example is [debug].
log4j: example level set to DEBUG
log4j: Level value for root is [debug].
log4j: root level set to DEBUG
log4j: Class name: [com.logentries.log4j.LogentriesAppender]
log4j:ERROR Could not create an Appender. Reported error follows.
java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "modifyThreadGroup")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:457)
at java.security.AccessController.checkPermission(AccessController.java:884)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at com.google.appengine.tools.development.DevAppServerFactory$CustomSecurityManager.checkPermission(DevAppServerFactory.java:429)
at com.google.appengine.tools.development.DevAppServerFactory$CustomSecurityManager.checkAccess(DevAppServerFactory.java:454)
at java.lang.ThreadGroup.checkAccess(ThreadGroup.java:315)
at java.lang.Thread.init(Thread.java:391)
at java.lang.Thread.init(Thread.java:349)
at java.lang.Thread.<init>(Thread.java:508)
at com.logentries.net.AsyncLogger$SocketAppender.<init>(AsyncLogger.java:496)
at com.logentries.net.AsyncLogger.<init>(AsyncLogger.java:336)
at com.logentries.net.AsyncLogger.<init>(AsyncLogger.java:343)
at com.logentries.log4j.LogentriesAppender.<init>(LogentriesAppender.java:24)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
at java.lang.Class.newInstance(Class.java:438)
at org.apache.log4j.xml.DOMConfigurator.parseAppender(DOMConfigurator.java:247)
at org.apache.log4j.xml.DOMConfigurator.findAppenderByName(DOMConfigurator.java:176)
at org.apache.log4j.xml.DOMConfigurator.findAppenderByReference(DOMConfigurator.java:191)
at org.apache.log4j.xml.DOMConfigurator.parseChildrenOfLoggerElement(DOMConfigurator.java:523)
at org.apache.log4j.xml.DOMConfigurator.parseRoot(DOMConfigurator.java:492)
at org.apache.log4j.xml.DOMConfigurator.parse(DOMConfigurator.java:1006)
at org.apache.log4j.xml.DOMConfigurator.doConfigure(DOMConfigurator.java:872)
at org.apache.log4j.xml.DOMConfigurator.doConfigure(DOMConfigurator.java:778)
at org.apache.log4j.helpers.OptionConverter.selectAndConfigure(OptionConverter.java:526)
at org.apache.log4j.LogManager.<clinit>(LogManager.java:127)
at org.apache.log4j.Logger.getLogger(Logger.java:104)
at hello.edu.appnamehidden.backend.RegistrationEndpoint.<clinit>(RegistrationEndpoint.java:36)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:344)
at com.google.api.server.spi.ServletInitializationParameters.getClassForName(ServletInitializationParameters.java:82)
at com.google.api.server.spi.ServletInitializationParameters.fromServletConfig(ServletInitializationParameters.java:51)
at com.google.api.server.spi.SystemServiceServlet.init(SystemServiceServlet.java:102)
at org.mortbay.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:440)
at org.mortbay.jetty.servlet.ServletHolder.getServlet(ServletHolder.java:339)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
at com.googlecode.objectify.cache.AsyncCacheFilter.doFilter(AsyncCacheFilter.java:59)
at com.googlecode.objectify.ObjectifyFilter.doFilter(ObjectifyFilter.java:49)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.api.socket.dev.DevSocketFilter.doFilter(DevSocketFilter.java:74)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.ResponseRewriterFilter.doFilter(ResponseRewriterFilter.java:127)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:34)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:63)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:125)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectRequest(DevAppServerModulesFilter.java:366)
at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectModuleRequest(DevAppServerModulesFilter.java:349)
at com.google.appengine.tools.development.DevAppServerModulesFilter.doFilter(DevAppServerModulesFilter.java:116)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:98)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:491)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:938)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
log4j: Appender named [le] not found.
Dec 31, 2014 1:50:36 AM com.google.api.server.spi.SystemServiceServlet init
INFO: SPI restricted: true
log4j: Finalizing appender named [null].
Working workaround solution
Thanks to @MarkLC help I was able to get LogEntries working on the local machine, check the answer and comments https://stackoverflow.com/a/27688486/546439, however, this never worked on the deployed App Engine.
I had to resort to using this gist https://gist.github.com/anlcan/9348751 and modifying it a little bit, it worked perfectly with App Engine when deployed.
Here's my code
public class LogEntriesHelper
{
private static Socket socket = null;
private static Lock lock = new ReentrantLock();
private static Condition condition = lock.newCondition();
private static final String LOG_TOKEN = "HIDDEN";
public static void log(String message)
{
try
{
if (socket == null || !socket.isConnected())
{
if (lock.tryLock())
{
socket = new Socket("data.logentries.com", 10000);
condition.signalAll();
lock.unlock();
}
else
{
condition.await();
}
}
Writer out = new OutputStreamWriter(socket.getOutputStream(), "UTF-8");
socket.setSoTimeout(10000);
out.write(LOG_TOKEN);
out.write(" ");
out.write(message);
out.write("\r\n");
out.flush();
}
catch (UnknownHostException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
Upvotes: 2
Views: 1263
Reputation: 201
I believe you need to place your config, either the xml or the properties inside src/main/resources for it to be picked up by log4j. You can just create that resources folder alongside java and webapp. Your config looks fine. Hope that helps.
After looking into App Engines sandbox, it seems it doesn't allow threads that outlive the request that spawned it. Your stack trace shows a RuntimePermission issue as that library spawns a background thread to send the log events to Logentries asynchronously. So this comes down to this library not being compatible with AppEngines sandbox.
You should be able to use log4j's built-in SyslogAppender to send logs synchronously to Logentries. I've successfully tested this locally but not from AppEngines sandbox with the below log4j.properties file:
log4j.rootLogger=DEBUG, syslog
log4j.appender.syslog=org.apache.log4j.net.SyslogAppender
log4j.appender.syslog.Facility=LOCAL7
log4j.appender.syslog.SyslogHost=api.logentries.com:10000
log4j.appender.syslog.layout=org.apache.log4j.PatternLayout
log4j.appender.syslog.layout.ConversionPattern=SECRET_TOKEN%p: (%F:%L) %x %m %n
Upvotes: 1