Mohamed Heiba
Mohamed Heiba

Reputation: 1833

Problems setting up LogEntries on App Engine

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

File structure in Android Studio

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

Answers (1)

MarkLC
MarkLC

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.

Update

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

Related Questions