2

我正在尝试在 Android Studio上的 App Engine 后端Java上设置日志

无论我做什么,我都会不断收到此错误消息

log4j:WARN 找不到记录器(根)的附加程序。

log4j:WARN 请正确初始化 log4j 系统。

log4j:WARN 有关详细信息,请参阅http://logging.apache.org/log4j/1.2/faq.html#noconfig

这是我的文件结构

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>

更新

我在这个问题Where to place log4j.xml中找到了一个非常有用的提示,基本上将 -Dlog4j.debug 放在 Java VM 参数中并在调试模式下运行 App Engine。它准确地告诉我它是否找到了 log4j.xml。经过多次试验和错误,当我将它放在 WEB-INF/classes 下时找到它,现在我可以准确地看到我遇到的错误的完整堆栈跟踪

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].

工作变通解决方案

感谢@MarkLC 的帮助,我能够让 LogEntries 在本地机器上运行,检查答案和评论https://stackoverflow.com/a/27688486/546439,但是,这从未在部署的 App Engine 上工作。

我不得不求助于使用这个要点https://gist.github.com/anlcan/9348751并对其进行一些修改,它在部署时与 App Engine 完美配合。

这是我的代码

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();
        }
    }
}
4

1 回答 1

1

我相信您需要将配置(xml 或属性)放在 src/main/resources 中,以便 log4j 获取它。您可以在 java 和 webapp 旁边创建该资源文件夹。你的配置看起来不错。希望有帮助。

更新

在查看 App Engines 沙箱后,似乎它不允许超过产生它的请求的线程。您的堆栈跟踪显示了一个 RuntimePermission 问题,因为该库生成了一个后台线程以将日志事件异步发送到 Logentries。所以这归结为这个库与 AppEngines 沙箱不兼容。

您应该能够使用 log4j 的内置 SyslogAppender 将日志同步发送到 Logentries。我已经使用以下 log4j.properties 文件在本地成功测试了这一点,但不是从 AppEngines 沙箱测试:

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
于 2014-12-29T12:01:14.123 回答