搭建Android日志系统 美团点评大前端Logan入门指南
目录前言总览快速开始下载官方源码使用IDEA打开Logan Server项目使用Docker下载MySQL镜像并启动容器运行Logan Server修改db.properties修改log4j.properties配置Maven使用Tomcat运行程序访问Logan Server运行Logan Site使用Visual Code打开LoganSite环境要求安装运行Logan-Android Sa
目录
前言
本文搬运自笔者的语雀博客,因前几天发现有网友点赞,想来还是有些帮助的,故分享出来,毕竟CSDN的SEO做的可太好了。
Logan 是美团点评集团推出的大前端日志系统。名称是 Log 和 An 的组合,代表个体日志服务,同时也是金刚狼大叔的大名。
总览
Logan 开源的是一整套日志体系,包括日志的收集存储,上报分析以及可视化展示。我们提供了五个组件,包括端上日志收集存储 、iOS SDK、Android SDK、Web SDK,后端日志存储分析 Server,日志分析平台 LoganSite。并且提供了一个 Flutter 插件Flutter 插件。
整体架构
快速开始
这里并不是官方文档的搬运,而是手把手教学,把日志系统搭建起来运行,只是看文档的话,确实会有些步骤卡住,不能解决。本文算是对官方文档的一个补充,也是对Github Issues一些问题的回答。
工欲善其事,必先利其器。这里需要小伙伴们先准备好以下工具:Linux开发环境(Window系统也行),Npm,Node.js, Yarn,Java8,IDEA ,Docker,AndroidStudio,Android手机一台。
好的,假装你准备好了,继续往下看。
下载官方源码
第一步,当然是下载源码了。如果使用Github不顺畅,可以参考以下方式:
推荐 SwitchHosts 工具管理 hosts,访问Github更方便。
使用方法,添加一个Hosts,参考下方内容填写:
Title: 随意
Type: Remote
URL: https://raw.hellogithub.com/hosts
Auto Refresh: 最好选 1 hour
工具来源:
https://github.com/521xueweihan/GitHub520
https://github.com/oldj/SwitchHosts
我这里把源码下载本地目录:/work/LogCenter/,解压,同时我还新建两个目录applogs和MySql等下需要用到。
使用IDEA打开Logan Server项目
使用IDEA打开Logan Sever项目备用,目录:/work/LogCenter/Logan/Logan/Server。
如果看官方文档,这里官方只给了创建表的sql语句,我表示很方,由于需要使用到MySQL数据库,所以这里介绍使用Docker搭建MySQL环境,不感兴趣的小伙伴请跳过此章节。
使用Docker下载MySQL镜像并启动容器
Docker怎么安装不用我说了吧。
链接走起自己看:Docker 教程 | 菜鸟教程
打开命令行终端,输入:docker pull mysql:5.7,回车执行,如下:
pc:~$ docker pull mysql:5.7 5.7: Pulling from library/mysql 33847f680f63: Already exists 5cb67864e624: Already exists 1a2b594783f5: Already exists b30e406dd925: Already exists 48901e306e4c: Already exists 603d2b7147fd: Already exists 802aa684c1c4: Already exists 5b5a19178915: Pull complete f9ce7411c6e4: Pull complete f51f6977d9b2: Pull complete aeb6b16ce012: Pull complete Digest: sha256:be70d18aedc37927293e7947c8de41ae6490ecd4c79df1db40d1b5b5af7d9596 Status: Downloaded newer image for mysql:5.7 docker.io/library/mysql:5.7
等待镜像下载完成。输入:docker images,查看镜像如下:
pc:~$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE kibana elastdocker-7.12.0 5ffdef382e6f 2 days ago 1.05GB logstash elastdocker-7.12.0 97fe3f5ae942 2 days ago 971MB elasticsearch elastdocker-7.12.0 1ad2d4e4b508 2 days ago 830MB elastic_certs latest 1ad2d4e4b508 2 days ago 830MB elastic_keystore latest 1ad2d4e4b508 2 days ago 830MB docker.elastic.co/beats/metricbeat 7.14.0-arm64 9dc075992137 13 days ago 1.19GB docker.elastic.co/beats/metricbeat 7.14.0 e3583bac930e 13 days ago 517MB mysql 5.7 8cf625070931 3 weeks ago 448MB mysql latest c60d96bd2b77 3 weeks ago 514MB docker.elastic.co/kibana/kibana 7.12.0 7a6b1047dd48 4 months ago 1.05GB docker.elastic.co/elasticsearch/elasticsearch 7.12.0 9337ed510a0c 4 months ago 830MB docker.elastic.co/logstash/logstash 7.12.0 c283394286f5 4 months ago 971MB jenkins v1.0.0 fab8efdd0aef 14 months ago 6.12GB jenkins test 1eb52b79643e 14 months ago 978MB hub.c.163.com/public/ubuntu 16.04-tools 1196ea15dad6 4 years ago 336MB
看到了吗?有一行:mysql 5.7 就是我们刚下载的镜像。接下来,我们编写docker-compose配置用于启动mysql:5.7容器。
在MySql目录新建mysql-5.7.yml,编写内容如下:
version: '2.0' services: mysql: container_name: "logan-mysql-5.7" environment: MYSQL_ROOT_PASSWORD: "123456" image: "mysql:5.7" restart: always ports: - 3316:3306
都看得懂吧,不懂先学习:Docker Compose | 菜鸟教程
命令行终端进入/home/work/LogCenter/MySql目录
输入命令:docker-compose -f mysql-5.7.yml up -d
/home/work/LogCenter/MySql$ docker-compose -f mysql-5.7.yml up -d
Creating network "mysql_default" with the default driver
Creating logan-mysql-5.7 ... done
输入命令:docker-compose ps或者docker ps可以查看启动的容器,state是Up代表正在运行。
/home/work/LogCenter/MySql$ docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------------------
logan-mysql-5.7 docker-entrypoint.sh mysqld Up 0.0.0.0:3316->3306/tcp, 33060/tcp
这时候使用Navicat或者DBeaver连接测试下,端口号和密码见 mysql-5.7.yml,成功。
有时候不那么幸运。连接不上的原因,往往是密码错误,或者远程登录限制了ip,这时候需要进入MySQL容器内部,连接数据库修改下。
登录成功,新建一个数据库,名为logan,执行官方给的sql,创建对应的表。对应的sql语句在这个位置:
到这里,MySQL的开发环境就搭好了。
运行Logan Server
到这一步,终于可以运行了。Logan Server是使用Maven管理的项目,所以导入项目的时候,要选择Maven。
修改db.properties
修改IP为1270.0.1,port为3316,database为logan,账号为root,密码为123456,根据你的msql配置来就行了。
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3316/logan?characterEncoding=UTF8&allowMultiQueries=true&socketTimeout=60000&autoReconnect=true jdbc.username=root jdbc.password=123456
修改log4j.properties
修改log4j.appender.R.File=/home/lb/work/LogCenter/applogs,也就是前面准备工作,创建的目录。
log4j.rootLogger=ERROR,R,stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n log4j.appender.R=org.apache.log4j.DailyRollingFileAppender log4j.appender.R.File=/home/lb/work/LogCenter/applogs/logan.log log4j.appender.R.layout=org.apache.log4j.PatternLayout log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n
配置Maven使用Tomcat运行程序
这个时候还不能运行程序,需要配置下。
依次点 Add Configuration--> + Maven + OK。
填入Command line填入tomcat:run,点OK即可。
然后就可以点绿色三角形按钮,运行程序了。
我们试下运行,报错了,果然too young too simple。
报了这个错误:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project logan-web: Fatal error compiling
经过一番搜索,说是Java版本不一致导致的:
解决Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile_分享传递价值-CSDN博客
好吧,查看下pom.xml,并没有Java版本的配置。那就从File-->Project Structure进去设置下Project SDK改为1.8的版本。
再次运行,看起来好像成功了。
请记住图中Sever的Url地址: http://localhost:8080/logan-web,就下就用到了。
访问Logan Server
打开浏览器,访问控制台打印的服务器Url:http://localhost:8080/logan-web,竟然报错了,心累有没有。
再看下控制台输出:
[INFO] [INFO] --------------------< com.meituan.logan:logan-web >--------------------- [INFO] Building logan-web 1.0-SNAPSHOT [INFO] --------------------------------[ war ]--------------------------------- [INFO] [INFO] >>> tomcat-maven-plugin:1.1:run (default-cli) > compile @ logan-web >>> [INFO] [INFO] --- maven-resources-plugin:2.5:resources (default-resources) @ logan-web --- [debug] execute contextualize [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 7 resources [INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ logan-web --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] <<< tomcat-maven-plugin:1.1:run (default-cli) < compile @ logan-web <<< [INFO] [INFO] [INFO] --- tomcat-maven-plugin:1.1:run (default-cli) @ logan-web --- [INFO] Running war on http://localhost:8080/logan-web [INFO] Using existing Tomcat server configuration at /home/work/IdeaProjects/Logan-master/Logan/Server/target/tomcat 八月 13, 2021 6:39:29 下午 org.apache.catalina.startup.Embedded start 信息: Starting tomcat server 八月 13, 2021 6:39:29 下午 org.apache.catalina.core.StandardEngine start 信息: Starting Servlet Engine: Apache Tomcat/6.0.29 八月 13, 2021 6:39:30 下午 org.apache.catalina.core.ApplicationContext log 信息: Initializing Spring root WebApplicationContext *********post initializaiton *********post initializaiton 八月 13, 2021 6:39:32 下午 org.apache.catalina.core.ApplicationContext log 信息: Initializing Spring DispatcherServlet 'mvc-dispatcher' 八月 13, 2021 6:39:32 下午 org.apache.coyote.http11.Http11Protocol init 信息: Initializing Coyote HTTP/1.1 on http-8080 八月 13, 2021 6:39:32 下午 org.apache.coyote.http11.Http11Protocol start 信息: Starting Coyote HTTP/1.1 on http-8080 八月 13, 2021 6:40:28 下午 org.apache.jasper.compiler.JDTCompiler$1 findType 严重: Compilation error org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException at org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader.<init>(ClassFileReader.java:342) at org.apache.jasper.compiler.JDTCompiler$1.findType(JDTCompiler.java:206) at org.apache.jasper.compiler.JDTCompiler$1.findType(JDTCompiler.java:163) at org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment.askForType(LookupEnvironment.java:96) at org.eclipse.jdt.internal.compiler.lookup.UnresolvedReferenceBinding.resolve(UnresolvedReferenceBinding.java:49) at org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding.resolveType(BinaryTypeBinding.java:97) at org.eclipse.jdt.internal.compiler.lookup.PackageBinding.getTypeOrPackage(PackageBinding.java:167) at org.eclipse.jdt.internal.compiler.lookup.Scope.getType(Scope.java:2187) at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.resolve(TypeDeclaration.java:974) at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.resolve(TypeDeclaration.java:1164) at org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration.resolve(CompilationUnitDeclaration.java:366) at org.eclipse.jdt.internal.compiler.Compiler.process(Compiler.java:623) at org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:392) at org.apache.jasper.compiler.JDTCompiler.generateClass(JDTCompiler.java:429) at org.apache.jasper.compiler.Compiler.compile(Compiler.java:349) at org.apache.jasper.compiler.Compiler.compile(Compiler.java:327) at org.apache.jasper.compiler.Compiler.compile(Compiler.java:314) at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:592) at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:317) at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313) at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260) at javax.servlet.http.HttpServlet.service(HttpServlet.java:717) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at com.meituan.logan.web.filter.CORSFilter.doFilter(CORSFilter.java:47) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) at java.lang.Thread.run(Thread.java:748) 八月 13, 2021 6:40:28 下午 org.apache.catalina.core.StandardWrapperValve invoke 严重: Servlet.service() for servlet jsp threw exception org.apache.jasper.JasperException: Unable to compile class for JSP: An error occurred at line: 1 in the generated java file The type java.io.ObjectInputStream cannot be resolved. It is indirectly referenced from required .class files Stacktrace: at org.apache.jasper.compiler.DefaultErrorHandler.javacError(DefaultErrorHandler.java:92) at org.apache.jasper.compiler.ErrorDispatcher.javacError(ErrorDispatcher.java:330) at org.apache.jasper.compiler.JDTCompiler.generateClass(JDTCompiler.java:439) at org.apache.jasper.compiler.Compiler.compile(Compiler.java:349) at org.apache.jasper.compiler.Compiler.compile(Compiler.java:327) at org.apache.jasper.compiler.Compiler.compile(Compiler.java:314) at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:592) at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:317) at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313) at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260) at javax.servlet.http.HttpServlet.service(HttpServlet.java:717) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at com.meituan.logan.web.filter.CORSFilter.doFilter(CORSFilter.java:47) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) at java.lang.Thread.run(Thread.java:748)
很棒,果然不是搞服务器开发的,运行个项目都这么坎坷。
度娘搜索:org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException
说Tomcat版本太低了:
Tomcat 启动异常:org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException
很好,万能的度娘。升级Tomcat版本试下。在pom.xml中配置tomcat7插件。
<plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8888</port> </configuration> </plugin>
添加配置后点下Maven同步。
接着编辑Maven的Command Line为:tomcat7:run,点击OK保存。
然后接着运行就可以了。
当然,你可以通过右边的Maven的Tomcat7插件直接运行,随你喜欢。
使用Tomcat7可能会有下面的报错。
八月 13, 2021 6:20:35 下午 org.apache.catalina.core.StandardService startInternal 信息: Starting service Tomcat 八月 13, 2021 6:20:35 下午 org.apache.catalina.core.StandardEngine startInternal 信息: Starting Servlet Engine: Apache Tomcat/7.0.47 八月 13, 2021 6:20:37 下午 org.apache.catalina.startup.ContextConfig processAnnotationsJar 严重: Unable to process Jar entry [module-info.class] from Jar [jar:file:/home/nxg/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.10.1/jackson-annotations-2.10.1.jar!/] for annotations org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 19 at org.apache.tomcat.util.bcel.classfile.Constant.readConstant(Constant.java:133) at org.apache.tomcat.util.bcel.classfile.ConstantPool.<init>(ConstantPool.java:60) at org.apache.tomcat.util.bcel.classfile.ClassParser.readConstantPool(ClassParser.java:209) at org.apache.tomcat.util.bcel.classfile.ClassParser.parse(ClassParser.java:119) at org.apache.catalina.startup.ContextConfig.processAnnotationsStream(ContextConfig.java:2134) at org.apache.catalina.startup.ContextConfig.processAnnotationsJar(ContextConfig.java:2010) at org.apache.catalina.startup.ContextConfig.processAnnotationsUrl(ContextConfig.java:1976) at org.apache.catalina.startup.ContextConfig.processAnnotations(ContextConfig.java:1961) at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1319) at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:878) at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:376) at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119) at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5322) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)
百度搜索到相关文章说这个没有影响,实际测试验证这个报错确实没有影响,先跳过。
当你可能还是遇到下面的问题。
提示:Failed to execute goal org.codehaus.mojo:tomcat-maven-plugin:1.1:run (default-cli) on project logan-web: Could not start Tomcat
方法也是尝试使用tomcat7版本运行。
浏览器刷新下网页,输出:hello, logan,感觉棒极了,就是着这种feel。
运行Logan Site
运行完后端,就轮到前端了。准备好Node.js开发环境,Npm,Yarn啥的不能少,这里还是稍微提下一下遇到的坑。
Npm很慢,需要设置淘宝镜像源。教程见:npm更换成淘宝镜像源以及cnpm
设置镜像源也不要使用npm install ,直接用这种方式:
npm config set registry https://registry.npm.taobao.org
使用Visual Code打开LoganSite
使用Visual Code打开LoganSite备用。
环境要求
Node: ^10.15.3 yarn: ^1.15.2 或 npm ^6.12.0
安装
本地运行
在LoganSite根目录下创建文件.env.development
,并在其中指定API_BASE_URL环境变量改为:
API_BASE_URL=http://localhost:8080/logan-web
没错,这个url就是运行Logan Server里控制台打印的URL。
然后LoganSite根目录执行以下命令,或者执行cd命令先进入LoganSite根目录。
$ yarn $ yarn start
为啥不推荐用npm,嗯,谁用谁知道。
注意:.env.development
一定要放在LoganSite根目录下,填写的url必须是Logan Server里控制台打印的URL。
如果你遇到了跟Github Issue相同的问题:
1.LoganSite启动后提示错误:请求出错Network Error #323。
2.LoganSite启动后提示错误:LoganSite 接入时文件加载404 #219。
请按照上述方式检查修改。
F12打开控制台,点Network选项卡,通常都是:
http://localhost:8080/logan-web/logan/latest.json
这个url请求报错,你看看的情况是不是这个问题。
运行Logan-Android Sample
AndroidStudio直接导入Logan-Android项目,由于依赖了Android-SDK源码,因此编译需要设置下NDK路径,要求NDK版本小于等于16.1.4479499。在Logan-Android根目录下的local.properties加入ndk.dir=/work/android/android-ndk-r15c,根据要求填入你的NDK路径。
## This file must *NOT* be checked into Version Control Systems, # as it contains information specific to your local configuration. # # Location of the SDK. This is only used by Gradle. # For customization when using a Version Control System, please read the # header note. #Wed Aug 11 18:04:17 CST 2021 sdk.dir=/work/android/android-sdk-linux ndk.dir=/work/android/android-ndk-r15c
然后修改test.logan.dianping.com.logan.RealSendLogRunnable这里的url如下图:
完整代码如下:
/*
* Copyright (c) 2018-present, 美团点评
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package test.logan.dianping.com.logan;
import android.text.TextUtils;
import android.util.Log;
import com.dianping.logan.SendLogRunnable;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
public class RealSendLogRunnable extends SendLogRunnable {
private static final String TAG = "RealSendLogRunnable";
private String mUploadLogUrl = "http://192.168.1.139:8080/logan-web/logan/upload.json";
@Override
public void sendLog(File logFile) {
boolean success = doSendFileByAction(logFile);
Log.d("上传日志测试", "日志上传测试结果:" + success);
// Must Call finish after send log
finish();
if (logFile.getName().contains(".copy")) {
logFile.delete();
}
}
public void setIp(String ip) {
mUploadLogUrl = "http://" + ip + ":8080/logan-web/logan/upload.json";
}
private HashMap<String, String> getActionHeader() {
HashMap<String, String> map = new HashMap<>();
map.put("Content-Type", "binary/octet-stream"); //二进制上传
map.put("client", "android");
return map;
}
/**
* 主动上报
*/
private boolean doSendFileByAction(File logFile) {
boolean isSuccess = false;
try {
FileInputStream fileStream = new FileInputStream(logFile);
byte[] backData = doPostRequest(mUploadLogUrl, fileStream, getActionHeader());
isSuccess = handleSendLogBackData(backData);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return isSuccess;
}
private byte[] doPostRequest(String url, InputStream inputData, Map<String, String> headerMap) {
Log.i(TAG, "doPostRequest: url " + url);
int statusCode = -1;
byte[] data = null;
OutputStream outputStream = null;
InputStream inputStream = null;
HttpURLConnection c = null;
ByteArrayOutputStream back;
byte[] Buffer = new byte[2048];
try {
java.net.URL u = new URL(url);
c = (HttpURLConnection) u.openConnection();
if (c instanceof HttpsURLConnection) {
((HttpsURLConnection) c).setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
}
Set<Map.Entry<String, String>> entrySet = headerMap.entrySet();
for (Map.Entry<String, String> tempEntry : entrySet) {
c.addRequestProperty(tempEntry.getKey(), tempEntry.getValue());
}
c.setReadTimeout(15000);
c.setConnectTimeout(15000);
c.setDoInput(true);
c.setDoOutput(true);
c.setRequestMethod("POST");
outputStream = c.getOutputStream();
int i;
while ((i = inputData.read(Buffer)) != -1) {
outputStream.write(Buffer, 0, i);
}
outputStream.flush();
statusCode = c.getResponseCode();
if (statusCode == 200) {
back = new ByteArrayOutputStream();
inputStream = c.getInputStream();
while ((i = inputStream.read(Buffer)) != -1) {
back.write(Buffer, 0, i);
}
data = back.toByteArray();
}
} catch (ProtocolException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputData != null) {
try {
inputData.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (c != null) {
c.disconnect();
}
}
Log.d(TAG, "log send completed, http statusCode : " + statusCode);
return data;
}
/**
* 处理上传日志接口返回的数据
*/
private boolean handleSendLogBackData(byte[] backData) throws JSONException {
boolean isSuccess = false;
if (backData != null) {
String data = new String(backData);
if (!TextUtils.isEmpty(data)) {
JSONObject jsonObj = new JSONObject(data);
if (jsonObj.optBoolean("success", false)) {
isSuccess = true;
}
}
}
return isSuccess;
}
}
注意:IP和端口号需要换成对应的Logan Server的IP和端口号,我这里Logan Server控制台打印的是:http://localhost:8080/logan-web,但Logan-Android Sample是运行在其他设备手上的,所以这里的localhost需要改成Logan Server运行环境的实际IP(局域网或者服务器公网IP),并且保证
Logan-Android Sample运行的设备能够访问Logan Server的实际IP。
还有一个地方,也建议修改,test.logan.dianping.com.logan.MainActivity的loganSendByDefault方法,这里填的Logan Server Url是美团点评官方平台的,但是已经无法访问了,换成自己的方便测试。
代码如下:
private void loganSendByDefault() {
String buildVersion = "";
String appVersion = "";
try {
PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
appVersion = pInfo.versionName;
buildVersion = String.valueOf(pInfo.versionCode);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
//final String url = "https://openlogan.inf.test.sankuai.com/logan/upload.json";
final String url = "http://192.168.1.139:8080部分/logan-web/logan/upload.json";
SimpleDateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd");
final String date = dataFormat.format(new Date(System.currentTimeMillis()));
Logan.s(url, date, "1", "logan-test-unionid", "deviceId", buildVersion, appVersion, new SendLogCallback() {
@Override
public void onLogSendCompleted(int statusCode, byte[] data) {
final String resultData = data != null ? new String(data) : "";
Log.d(TAG, "日志上传结果, http状态码: " + statusCode + ", 详细: " + resultData);
}
});
}
准备就绪,运行Logan-Android Sample,再次强调设备必须能够访问Logan Server的实际IP(同一个局域网或者服务器使用公网IP),然后App界面按钮全部点一遍,看到类似以下日志就说明,日志上传成功了。
2021-08-16 11:55:58.202 17982-17998/test.logan.dianping.com.logan D/test.logan.dianping.com.logan.MyApplication: clogan > cmd : clogan_init | code : -1010 2021-08-16 11:55:58.202 17982-17998/test.logan.dianping.com.logan D/LoganThread: Logan write start 2021-08-16 11:55:58.208 17982-17998/test.logan.dianping.com.logan D/test.logan.dianping.com.logan.MyApplication: clogan > cmd : clogan_open | code : -2010 2021-08-16 11:55:58.209 17982-17998/test.logan.dianping.com.logan D/test.logan.dianping.com.logan.MyApplication: clogan > cmd : clogan_write | code : -4010 2021-08-16 11:55:58.209 17982-17998/test.logan.dianping.com.logan D/LoganThread: Logan write start 2021-08-16 11:55:58.209 17982-17998/test.logan.dianping.com.logan D/LoganThread: Logan write start 2021-08-16 11:55:58.309 17982-17999/test.logan.dianping.com.logan I/mali_so: [File] : hardware/arm/maliT760/driver/product/base/src/mali_base_kbase.c; [Line] : 978; [Func] : base_context_deal_with_version_affairs_rk_ext; arm_release_ver of this mali_so is 'r14p0-01rel0', rk_so_ver is '5@0'. 2021-08-16 11:55:58.310 17982-17999/test.logan.dianping.com.logan D/mali_so: [File] : hardware/arm/maliT760/driver/product/base/src/mali_base_kbase.c; [Line] : 983; [Func] : base_context_deal_with_version_affairs_rk_ext; current process is NOT sf, to bail out. 2021-08-16 11:55:58.317 17982-17999/test.logan.dianping.com.logan I/OpenGLRenderer: Initialized EGL, version 1.4 2021-08-16 11:55:58.317 17982-17999/test.logan.dianping.com.logan D/OpenGLRenderer: Swap behavior 1 2021-08-16 11:55:58.328 17982-17999/test.logan.dianping.com.logan D/mali_winsys: EGLint new_window_surface(egl_winsys_display*, void*, EGLSurface, EGLConfig, egl_winsys_surface**, egl_color_buffer_format*, EGLBoolean) returns 0x3000 2021-08-16 11:56:00.225 17982-18031/test.logan.dianping.com.logan D/test.logan.dianping.com.logan.MainActivity: times : 0 2021-08-16 11:56:00.225 17982-17998/test.logan.dianping.com.logan D/LoganThread: Logan write start 2021-08-16 11:56:00.231 17982-18031/test.logan.dianping.com.logan D/test.logan.dianping.com.logan.MainActivity: times : 1 2021-08-16 11:56:01.339 17982-18035/test.logan.dianping.com.logan I/RealSendLogRunnable: doPostRequest: url http://192.168.1.139:8080/logan-web/logan/upload.json 2021-08-16 11:56:01.342 17982-18035/test.logan.dianping.com.logan D/NetworkSecurityConfig: No Network Security Config specified, using platform default 2021-08-16 11:56:01.608 17982-18035/test.logan.dianping.com.logan D/RealSendLogRunnable: log send completed, http statusCode : 200 2021-08-16 11:56:01.609 17982-18035/test.logan.dianping.com.logan D/上传日志测试: 日志上传测试结果:false 2021-08-16 11:56:01.793 17982-17998/test.logan.dianping.com.logan D/LoganThread: Logan send start 2021-08-16 11:56:01.793 17982-17998/test.logan.dianping.com.logan D/LoganThread: prepare log file 2021-08-16 11:56:01.794 17982-17998/test.logan.dianping.com.logan D/LoganThread: Logan flush start 2021-08-16 11:56:01.799 17982-18035/test.logan.dianping.com.logan I/SendLogDefaultRunnable: doPostRequest: url = http://192.168.1.139:8080/logan-web/logan/upload.json 2021-08-16 11:56:01.848 17982-18035/test.logan.dianping.com.logan D/SendLogDefaultRunnable: log send completed, http statusCode : 200 2021-08-16 11:56:01.848 17982-18035/test.logan.dianping.com.logan D/test.logan.dianping.com.logan.MainActivity: 日志上传结果, http状态码: 200, 详细: {"code":200,"msg":null,"data":"/logan/downing?name=1_deviceId_1629043200000_23eb244a-7a65-4934-9095-26b2f346de43.log"}
我们查看数据库验证下:
查到了两条日志记录,再回到http://localhost:3000/,F5刷新,确实看到了两条日志记录。
点击查看日志详情,没毛病。
感谢阅读,Logan手把手入门指南到这结束了,更多问题欢迎留言交流。
部分Github Issue解决方法
请求出错Network Error #323。
解决方法:
在LoganSite根目录下创建文件.env.development
,并在其中指定API_BASE_URL环境变量改为:
API_BASE_URL=http://localhost:8080/logan-web
注意,这个API_BASE_URL就是运行Logan Server里控制台打印的URL,如下图;
注意:.env.development
一定要放在LoganSite根目录下,并且检查src/common/api.js里的BASE_URL变量是否指向.env.development配置的变量。
const BASE_URL = process.defineEnv.API_BASE_URL; const API_TIME_OUT = 30000; let pendingRequests = []; // axios instance const instance = axios.create({ baseURL: BASE_URL, timeout: API_TIME_OUT, withCredentials: true });
LoganSite 接入时文件加载404 #219。
解决方法:同#323。
Server SDK 有更详细的教程吗? #315
解决方法:查看本文运行Logan Server章节内容点我跳转。
更多推荐
所有评论(0)