我正在尝试在 Android Studio上的 App Engine 后端Java上设置日志
无论我做什么,我都会不断收到此错误消息
log4j:WARN 找不到记录器(根)的附加程序。
log4j:WARN 请正确初始化 log4j 系统。
log4j:WARN 有关详细信息,请参阅http://logging.apache.org/log4j/1.2/faq.html#noconfig。
这是我的文件结构
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();
}
}
}