-
springboot 整合logback实现日志出入到不同文件当中(含sql输出到制定文件中)
2021-03-24 16:45:37在配置文件中配置了Mybatis的相关参数,将sql语句输入到控制台上,但是在生产上我们为了排错或者查看sql的执行过程,就需要查看日志,所以Mybatis执行sql不仅要能在控制台打印输出,还要能写入日志文件待查。...一 概述
1.1 概述
我们在本地开发,在配置文件中配置了Mybatis的相关参数,将sql语句输入到控制台上,但是在生产上我们为了排错或者查看sql的执行过程,就需要查看日志,所以Mybatis执行sql不仅要能在控制台打印输出,还要能写入日志文件待查。之前看过的好多博客只是解决了日志向控制台打印的问题。怎么将日志写到制定的文件,遇到了好了问题,无法将日志写到制定的文件中,
麻蛋,网上一堆资料,都是瞎比咧咧,解决不了问题,自己通过专研,终于实现了将日志输入到制定的文件当中。由于Mybatis执行sql的日志级别为DEBUG,一般生产上需要的日志级别为INFO及以上。如果将DEBUG级别日志全部写入日志文件,会造成日志查问题的速度降低,难度大大提高。所以建议:将Mybatis执行sql的日志只能向更高日志级别的日志文件追加或单独写入一个文件。
1.2 解决办法
当时配置好springboot和logback,无法将mybaits的sql语句写入到制定文件的原因是,日志的输出方式没有配对
将 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 改为:log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
应该配置成:
1.3 logback中onmatch与onmismatch的区别
二 案例演示
2.1 项目结构
2.2.代码说明
2.2.1pom文件
<!-- springBoot的启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.0.1.RELEASE</version> </dependency> <!-- web启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> <version>2.0.1.RELEASE</version> </dependency> <!-- Mybatis启动器 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency> <!-- mysql数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.3</version> </dependency> <!-- druid数据库连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.9</version> </dependency>
2.2.2 controller层
package com.ljf.spring.boot.demo.persistence.controller; import com.ljf.spring.boot.demo.persistence.model.Users; import com.ljf.spring.boot.demo.persistence.service.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import java.util.List; /** * @ClassName: UserController * @Description: TODO * @Author: liujianfu * @Date: 2020/07/29 15:45:36 * @Version: V1.0 **/ @Controller @RequestMapping("/users") public class UserController { private static final Logger logger = LoggerFactory.getLogger(UserController.class); @Autowired private UserService usersService; /** * 页面跳转 */ @RequestMapping("/{page}") public String showPage(@PathVariable String page){ System.out.println("进来了!!!"+page); return page; } /** * 添加用户 */ @RequestMapping("/addUser") public String addUser(Users users){ System.out.println("users:"+users.getName()); this.usersService.addUser(users); return "ok"; } /** * 查询全部用户 */ @RequestMapping("/findUserAll") public String findUserAll(Model model){ logger.info("=========================================查询全部用户信息!!!!!!!!!!!!!!!!!!!!!"); List<Users> list = this.usersService.findUserAll(); model.addAttribute("list", list); return "showUsers"; } /** * 根据用户id查询用户 */ @RequestMapping("/findUserById") public String findUserById(Integer id,Model model){ Users user = this.usersService.findUserById(id); model.addAttribute("user", user); System.out.println("update:"+user); return "updateUser"; } /** * 更新用户 */ @RequestMapping("/editUser") public String editUser(Users users){ this.usersService.updateUser(users); return "ok"; } /** * 删除用户 */ @RequestMapping("/delUser") public String delUser(Integer id){ this.usersService.deleteUserById(id); return "redirect:/users/findUserAll"; //重定向页面 } }
2.2.3 dao层
package com.ljf.spring.boot.demo.persistence.dao; import com.ljf.spring.boot.demo.persistence.model.Users; import org.springframework.stereotype.Repository; import java.util.List; @Repository public interface UsersMapper { void insertUser(Users users); List<Users> selectUsersAll(); Users selectUsersById(Integer id); void updateUser(Users users); void deleteUserById(Integer id); }
2.2.4 其他层
其他层不是这篇博客的重点不在贴出,只贴出相应的结构图
2.3. 日志输入到不同文件
2.3.1 .application的配置文件
server: port: 8081 spring: datasource: driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/test_db username: root password: root type: com.alibaba.druid.pool.DruidDataSource mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.ljf.spring.boot.demo.persistence.model configuration: #增加打印sql语句,将日志写入到制定的日志文件当中 log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl #增加打印sql语句,一般用于本地开发测试 #log-impl: org.apache.ibatis.logging.stdout.StdOutImpl logging: config: classpath:logback-spring-fen.xml
2.3.2 logback.xml的配置
配置自己项目的dao层路径,日志级别为info
<?xml version="1.0" encoding="UTF-8"?> <configuration> <property name="LOG_PATH" value="../logs"/> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder charset="UTF-8"> <pattern>%date [%thread] %-5level %logger [%L] - %msg%n</pattern> </encoder> </appender> <!--sql日志--> <appender name="APP_SQL" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--活动日志输出路径示例--> <file>${LOG_PATH}/sql.log</file> <append>true</append> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>DEBUG</level> <!-- onMatch:意思是当前级别以及以上要怎么处理 --> <onMatch>ACCEPT</onMatch> <!-- onMismatch:意思是当前级别(不包括当前级别)以下要怎么处理 --> <onMismatch>DENY</onMismatch> </filter> <!--存档日志示例--> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_PATH}/%d{yyyy-MM-dd}/sql.%i.log </fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <!--日志大小可自定义--> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--存档天数可自定义--> <maxHistory>90</maxHistory> </rollingPolicy> <!--统一日志输出格式--> <encoder charset="UTF-8"> <pattern>%date [%thread] %-5level %logger [%L] - %msg%n</pattern> </encoder> </appender> <!--info日志--> <appender name="APP_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--活动日志输出路径示例--> <file>${LOG_PATH}/info.log</file> <append>true</append> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <!--存档日志示例--> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_PATH}/%d{yyyy-MM-dd}/info.%i.log </fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <!--日志大小可自定义--> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--存档天数可自定义--> <maxHistory>90</maxHistory> </rollingPolicy> <!--统一日志输出格式--> <encoder charset="UTF-8"> <pattern>%date [%thread] %-5level %logger [%L] - %msg%n</pattern> </encoder> </appender> <!--ERROR日志--> <appender name="APP_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}/error.log</file> <append>true</append> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_PATH}/%d{yyyy-MM-dd}/error.%i.log </fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <maxHistory>90</maxHistory> </rollingPolicy> <encoder charset="UTF-8"> <pattern>%date [%thread] %-5level %logger [%L] - %msg%n</pattern> </encoder> </appender> <!--<appender name="CatAppender" class="com.baojia.bike.config.CatLogbackAppender"></appender>--> <logger name="com.ljf.spring.boot.demo.persistence.dao" level="DEBUG"> <appender-ref ref="APP_SQL"/> </logger> <!--调试模式下可以改为debug--> <root level="INFO"> <!--<appender-ref ref="CatAppender" />--> <appender-ref ref="CONSOLE"/> <appender-ref ref="APP_ERROR"/> <appender-ref ref="APP_INFO"/> </root> </configuration>
2.3.3 执行访问,产生日志
看看日志目录:
logs和工程是平级的,进入logs文件夹后,可以看到产生了error,info,sql三种信息的日志文件
查看sql文件:
2.4 将日志输入到相同文件
2.4.1 application的配置文件
server: port: 8081 spring: datasource: driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/test_db username: root password: root type: com.alibaba.druid.pool.DruidDataSource mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.ljf.spring.boot.demo.persistence.model configuration: #增加打印sql语句,将日志写入到制定的日志文件当中 log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl #增加打印sql语句,一般用于本地开发测试 #log-impl: org.apache.ibatis.logging.stdout.StdOutImpl logging: 3config: classpath:logback-spring-fen.xml config: classpath:logback-spring-he.xml
2.4.2 logback配置文件
<?xml version="1.0" encoding="UTF-8"?> <configuration scan="true" scanPeriod="60 seconds" debug="false"> <property name="LOG_PATH" value="D:/spt-logback-demo-logs"/> <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> <property name="LOG_STDOUT_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/> <property name="LOG_FILE_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/> <!-- 输出到控制台 --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <!-- 输出的格式 --> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>${LOG_STDOUT_PATTERN}</pattern> </encoder> </appender> <!-- 生成日志文件 --> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 日志名称 --> <file>${LOG_PATH}/spt-logback.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>${LOG_PATH}/14-spt.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- 日志最大 50MB --> <maxFileSize>50MB</maxFileSize> <!-- 保存 30 天 --> <maxHistory>30</maxHistory> <!-- <totalSizeCap>10GB</totalSizeCap> <!– 总日志大小 –>--> </rollingPolicy> <encoder> <pattern>${LOG_FILE_PATTERN}</pattern> </encoder> </appender> <!-- <logger name="org.influxdb" level="INFO"/> --> <logger name="com.ljf.spring.boot.demo.persistence.dao" level="debug"/> <root level="INFO"> <appender-ref ref="CONSOLE"/> <appender-ref ref="FILE"/> </root> </configuration>
2..4.3 页面访问,产生日志
查看日志的目录:
查看日志:
2021-03-24 17:48:10.870 [main] INFO c.l.spring.boot.demo.persistence.App - Starting App on LAPTOP-VC53HCIP with PID 33028 (E:\springboot-project\spring-boot-demo\04-spt-tx-persistence-crud\target\classes started by jurfl in E:\springboot-project\spring-boot-demo) 2021-03-24 17:48:10.873 [main] INFO c.l.spring.boot.demo.persistence.App - No active profile set, falling back to default profiles: default 2021-03-24 17:48:10.933 [main] INFO o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext - Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@43bc63a3: startup date [Wed Mar 24 17:48:10 CST 2021]; root of context hierarchy 2021-03-24 17:48:12.146 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8081 (http) 2021-03-24 17:48:12.161 [main] INFO o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-8081"] 2021-03-24 17:48:12.169 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] 2021-03-24 17:48:12.170 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet Engine: Apache Tomcat/8.5.29 2021-03-24 17:48:12.174 [localhost-startStop-1] INFO o.a.c.core.AprLifecycleListener - The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [C:\Program Files\Java\jdk1.8.0_181\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;d:\app\as\product\12.1.0\dbhome_1\bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\Java\jdk1.8.0_181\bin;D:\apache-maven-3.6.0\bin;D:\apache-tomcat-8.5.6\bin;C:\Program Files\TortoiseSVN\bin;D:\mysql-5.7.21-winx64\bin;C:\Program Files\Git\bin;D:\xshell-manager\Xmanager 7\;D:\xshell-manager\Xshell 7\;D:\xshell-manager\Xftp 7\;D:\xshell-manager\Xlpd 7\;C:\Users\jurfl\AppData\Local\Microsoft\WindowsApps;;C:\Program Files\JetBrains\IntelliJ IDEA 2019.2.4\bin;;.] 2021-03-24 17:48:12.325 [localhost-startStop-1] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext 2021-03-24 17:48:12.325 [localhost-startStop-1] INFO o.s.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 1392 ms 2021-03-24 17:48:12.502 [localhost-startStop-1] INFO o.s.b.w.s.ServletRegistrationBean - Servlet dispatcherServlet mapped to [/] 2021-03-24 17:48:12.506 [localhost-startStop-1] INFO o.s.b.w.s.FilterRegistrationBean - Mapping filter: 'characterEncodingFilter' to: [/*] 2021-03-24 17:48:12.507 [localhost-startStop-1] INFO o.s.b.w.s.FilterRegistrationBean - Mapping filter: 'hiddenHttpMethodFilter' to: [/*] 2021-03-24 17:48:12.507 [localhost-startStop-1] INFO o.s.b.w.s.FilterRegistrationBean - Mapping filter: 'httpPutFormContentFilter' to: [/*] 2021-03-24 17:48:12.507 [localhost-startStop-1] INFO o.s.b.w.s.FilterRegistrationBean - Mapping filter: 'requestContextFilter' to: [/*] 2021-03-24 17:48:12.866 [main] INFO o.s.w.s.h.SimpleUrlHandlerMapping - Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2021-03-24 17:48:13.042 [main] INFO o.s.w.s.m.m.a.RequestMappingHandlerAdapter - Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@43bc63a3: startup date [Wed Mar 24 17:48:10 CST 2021]; root of context hierarchy 2021-03-24 17:48:13.146 [main] INFO o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/users/addUser]}" onto public java.lang.String com.ljf.spring.boot.demo.persistence.controller.UserController.addUser(com.ljf.spring.boot.demo.persistence.model.Users) 2021-03-24 17:48:13.147 [main] INFO o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/users/findUserAll]}" onto public java.lang.String com.ljf.spring.boot.demo.persistence.controller.UserController.findUserAll(org.springframework.ui.Model) 2021-03-24 17:48:13.147 [main] INFO o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/users/{page}]}" onto public java.lang.String com.ljf.spring.boot.demo.persistence.controller.UserController.showPage(java.lang.String) 2021-03-24 17:48:13.148 [main] INFO o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/users/findUserById]}" onto public java.lang.String com.ljf.spring.boot.demo.persistence.controller.UserController.findUserById(java.lang.Integer,org.springframework.ui.Model) 2021-03-24 17:48:13.148 [main] INFO o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/users/editUser]}" onto public java.lang.String com.ljf.spring.boot.demo.persistence.controller.UserController.editUser(com.ljf.spring.boot.demo.persistence.model.Users) 2021-03-24 17:48:13.148 [main] INFO o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/users/delUser]}" onto public java.lang.String com.ljf.spring.boot.demo.persistence.controller.UserController.delUser(java.lang.Integer) 2021-03-24 17:48:13.151 [main] INFO o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) 2021-03-24 17:48:13.152 [main] INFO o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) 2021-03-24 17:48:13.174 [main] INFO o.s.w.s.h.SimpleUrlHandlerMapping - Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2021-03-24 17:48:13.175 [main] INFO o.s.w.s.h.SimpleUrlHandlerMapping - Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2021-03-24 17:48:13.453 [main] INFO o.s.j.e.a.AnnotationMBeanExporter - Registering beans for JMX exposure on startup 2021-03-24 17:48:13.454 [main] INFO o.s.j.e.a.AnnotationMBeanExporter - Bean with name 'dataSource' has been autodetected for JMX exposure 2021-03-24 17:48:13.461 [main] INFO o.s.j.e.a.AnnotationMBeanExporter - Located MBean 'dataSource': registering with JMX server as MBean [com.alibaba.druid.pool:name=dataSource,type=DruidDataSource] 2021-03-24 17:48:13.473 [main] INFO o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-8081"] 2021-03-24 17:48:13.486 [main] INFO o.a.tomcat.util.net.NioSelectorPool - Using a shared selector for servlet write/read 2021-03-24 17:48:13.502 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8081 (http) with context path '' 2021-03-24 17:48:13.506 [main] INFO c.l.spring.boot.demo.persistence.App - Started App in 3.085 seconds (JVM running for 5.95) 2021-03-24 17:48:22.617 [http-nio-8081-exec-1] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring FrameworkServlet 'dispatcherServlet' 2021-03-24 17:48:22.618 [http-nio-8081-exec-1] INFO o.s.web.servlet.DispatcherServlet - FrameworkServlet 'dispatcherServlet': initialization started 2021-03-24 17:48:22.647 [http-nio-8081-exec-1] INFO o.s.web.servlet.DispatcherServlet - FrameworkServlet 'dispatcherServlet': initialization completed in 29 ms 2021-03-24 17:48:22.673 [http-nio-8081-exec-1] INFO c.l.s.b.d.p.c.UserController - =========================================查询全部用户信息!!!!!!!!!!!!!!!!!!!!! 2021-03-24 17:48:22.701 [http-nio-8081-exec-1] INFO c.alibaba.druid.pool.DruidDataSource - {dataSource-1} inited 2021-03-24 17:48:22.837 [http-nio-8081-exec-1] DEBUG c.l.s.b.d.p.d.U.selectUsersAll - ==> Preparing: select id,name,age from tb_users 2021-03-24 17:48:22.849 [http-nio-8081-exec-1] DEBUG c.l.s.b.d.p.d.U.selectUsersAll - ==> Parameters: 2021-03-24 17:48:22.861 [http-nio-8081-exec-1] DEBUG c.l.s.b.d.p.d.U.selectUsersAll - <== Total: 7 2021-03-24 17:48:30.972 [http-nio-8081-exec-3] DEBUG c.l.s.b.d.p.d.U.selectUsersById - ==> Preparing: select id,name,age from tb_users where id = ? 2021-03-24 17:48:30.972 [http-nio-8081-exec-3] DEBUG c.l.s.b.d.p.d.U.selectUsersById - ==> Parameters: 1(Integer) 2021-03-24 17:48:30.973 [http-nio-8081-exec-3] DEBUG c.l.s.b.d.p.d.U.selectUsersById - <== Total: 1
-
springboot 配置多库之后,mybatis在控制台不打印sql语句了
2019-05-05 09:54:49CONSOLE将日志信息输出到控制上,为方便开发测试使用 --> <!-- 日志记录器,日期滚动记录 --> <!-- 正在记录的日志文件的路径及文件名 --> ${LOG_PATH}/error_statisticserver.log <!-- 日志记录器的... -
IntelliJ IDEA中日志分类显示设置
2017-12-11 09:08:00说明:很遗憾,IDEA中无法实现日志分类查看,比如只能显示INFO级别的,但是...直接使用IDEA导入输出的日志文件,就可以实现比如logback配置了不向上传递导致控制台不能输出日志的查看。 参考: http://blog.csd...说明:很遗憾,IDEA中无法实现日志分类查看,比如只能显示INFO级别的,但是可以有搜索功能【Ctrl】+【F】。好像找不到好用的插件,Andorid Studio好像有一个插件可以。
解决方式:
直接使用IDEA导入输出的日志文件,就可以实现比如logback配置了不向上传递导致控制台不能输出日志的查看。
参考:
http://blog.csdn.net/yang292292/article/details/53353774
https://www.jetbrains.com/help/idea/2016.2/run-debug-configurations.html
https://www.jetbrains.com/help/idea/2016.2/setting-log-options.html
==>如有问题,请联系我:easonjim#163.com,或者下方发表评论。<== -
网管教程 从入门到精通软件篇.txt
2010-04-25 22:43:49如果不能在启动目录(默认为 %systemroot%System32)中找到该文件,将试着在 Windows 安装 CD 中找到它。如果有多引导系统的计算机,必须保证是在包含 Windows 的驱动器上使用该命令。 Diskpart 创建和删除硬盘... -
Unity 自定义Log系统
2018-08-14 20:36:43原因 1.测试跑IOS的时候,游戏卡死,但是却无法查看日志,因为必须将手机插在mac机器上,用xcode才能实时看日志。...1.让日志可以输出到3个地方:(1)控制台(2)界面 (3)文件 2.能输出游戏指定模块的日志 ...原因
1.测试跑IOS的时候,游戏卡死,但是却无法查看日志,因为必须将手机插在mac机器上,用xcode才能实时看日志。
2.Android虽然卡死后,可以再插上电脑,通过AndroidStudio查看已经输出的日志,但是也会遇到看不到日志,或者手机插上无法被ADB侦测的问题。
目标
1.让日志可以输出到3个地方:(1)控制台(2)界面 (3)文件
2.能输出游戏指定模块的日志
3.能输出特定级别的日志,如error,warning等
代码
注:UI组件YYUIWrapContent未贴上,如果需要使用,你们可以不使用输入到ui的功能。
using System.Collections.Generic; using System.IO; using UnityEngine; using UnityEngine.UI; public class DebugLog { public enum OutputModule { eNone, ePve = 1, eWonderland = 2, eTrial = 3, eMainScene = 4, eUI = 5, eOther = 6, ePveBase = 7, eMiniGame = 8, eGM = 9, eProxy = 10, eLoader = 11, eBattle = 12, eResLoad = 13, eNetWork = 14, eStory = 15, ePlatform = 16, } public enum OutputTarget { eNone, eConsole = 1, eUI = 2, eFile = 3, } public enum OutputLevel { eNone, eLog = 1, eLogWaning = 2, eLogError = 3, } //全局控制是否开启日志 public static bool isOpenLog; //控制输出的模块 private static int outputModule; //控制输出的目标 private static int outputTarget; //控制输出的等级 private static int outputLevel; //文件路径 private static string filePath; //ui显示最大缓存的日志数量 private const int MAX_LOG_NUM = 1000; private static List<string> logList = new List<string>(); //ui组件,实现循环滚动 private static YYUIWarpContent wrapContent; public static void Init(YYUIWarpContent uiContent) { Application.logMessageReceived += LogCallback; //获取文件路径 filePath = GetPath("LJSLogFile.txt"); //删除已存在的文件 if (File.Exists(filePath)) { File.Delete(filePath); } //获取ui组件 wrapContent = uiContent; //是否要输出日志 isOpenLog = true; //指定要输出哪些模块 SwitchModule(OutputModule.ePve, true); SwitchModule(OutputModule.eWonderland, true); SwitchModule(OutputModule.eTrial, true); SwitchModule(OutputModule.eMainScene, true); SwitchModule(OutputModule.eUI, true); SwitchModule(OutputModule.eOther, true); SwitchModule(OutputModule.ePveBase, true); SwitchModule(OutputModule.eMiniGame, true); SwitchModule(OutputModule.eGM, true); SwitchModule(OutputModule.eProxy, true); SwitchModule(OutputModule.eLoader, true); SwitchModule(OutputModule.eBattle, true); SwitchModule(OutputModule.eResLoad, true); SwitchModule(OutputModule.eNetWork, true); SwitchModule(OutputModule.eStory, true); SwitchModule(OutputModule.ePlatform, true); //指定要输出的目标 SwitchTarget(OutputTarget.eConsole, true); SwitchTarget(OutputTarget.eUI, true); //SwitchTarget(OutputTarget.eFile, true); //指定输出的级别 SwitchLevel(OutputLevel.eLog, true); SwitchLevel(OutputLevel.eLogWaning, true); SwitchLevel(OutputLevel.eLogError, true); } public static void LogCallback(string condition, string stackTrace, LogType type) { string result = ""; if (type == LogType.Error || type == LogType.Log || type == LogType.Warning) { result = condition; } else { result = string.Format("{0}\n{1}", condition, stackTrace); } OutputUI(result); OutputFile(result); } public static void Log(OutputModule type, string message) { if (!IsOuputLog(type, OutputLevel.eLog)) { return; } message = ModifyLog(message, 0); OutputConsole(message, 0); } public static void LogWarning(OutputModule type, string message) { if (!IsOuputLog(type, OutputLevel.eLogWaning)) { return; } message = ModifyLog(message, 1); OutputConsole(message, 1); } public static void LogError(OutputModule type, string message) { if (!IsOuputLog(type, OutputLevel.eLogError)) { return; } message = ModifyLog(message, 2); OutputConsole(message, 2); } private static void OutputConsole(string message, int type) { if(!IsOutputTarget(OutputTarget.eConsole)) { return; } if (type == 0) { Debug.Log(message); } else if (type == 1) { Debug.LogWarning(message); } else if (type == 2) { Debug.LogError(message); } } private static void OutputFile(string message) { if (!IsOutputTarget(OutputTarget.eFile)) { return; } FileStream fs = File.Open(filePath, FileMode.Append, FileAccess.Write); StreamWriter sw = new StreamWriter(fs); sw.WriteLine(message); sw.Close(); fs.Close(); } private static void OutputUI(string message) { if (!IsOutputTarget(OutputTarget.eUI)) { return; } if(logList.Count >= MAX_LOG_NUM) { logList.Clear(); } logList.Add(message); wrapContent.Init(logList.Count, (obj, index) => { Text text = obj.GetComponent<Text>(); text.text = logList[index]; }, null, false); } private static bool IsOuputLog(OutputModule type, OutputLevel level) { bool result = false; bool rule1 = (outputModule & (1 << (int)type)) > 0 ? true : false; bool rule2 = isOpenLog; bool rule3 = (outputLevel & (1 << (int)level)) > 0 ? true : false; if (rule1 && rule2 && rule3) { result = true; } return result; } private static bool IsOutputTarget(OutputTarget target) { bool result = false; result = (outputTarget & (1 << (int)target)) > 0 ? true : false; return result; } private static string ModifyLog(string message, int type) { string result = ""; switch (type) { case 0: { result += "common : "; } break; case 1: { result += "warning : "; } break; case 2: { result += "error : "; } break; } result += message; return result; } private static string GetPath(string name) { string path = ""; switch (Application.platform) { case RuntimePlatform.Android: case RuntimePlatform.IPhonePlayer: { path = Application.persistentDataPath + "/" + name; } break; case RuntimePlatform.OSXEditor: case RuntimePlatform.WindowsEditor: case RuntimePlatform.WindowsPlayer: { path = Application.dataPath + "/../" + name; } break; } return path; } public static void SwitchModule(OutputModule module, bool isOpen) { if (isOpen) { outputModule = outputModule | (1 << (int)module); } else { outputModule = outputModule & (~(1 << (int)module)); } } public static void SwitchTarget(OutputTarget target, bool isOpen) { if(isOpen) { outputTarget = outputTarget | (1 << (int)target); } else { outputTarget = outputTarget & (~(1 << (int)target)); } } public static void SwitchLevel(OutputLevel level, bool isOpen) { if (isOpen) { outputLevel = outputLevel | (1 << (int)level); } else { outputLevel = outputLevel & (~(1 << (int)level)); } } }
-
-
C++基础(十二)一个宏使用的坑
2020-12-30 14:47:40虽然C++一直在强调尽量少用宏,但是宏确实是个好东西,会使代码很简洁,使人欲罢不能。 近期出现一个无法理解的异常,找了很长时间,结果发现是调用的别人的宏导致的,差点...而开发环境下,直接打印到控制台更方便查虽然C++一直在强调尽量少用宏,但是宏确实是个好东西,会使代码很简洁,使人欲罢不能。
近期出现一个无法理解的异常,找了很长时间,结果发现是调用的别人的宏导致的,差点吐血。
实际工作中,日志是定位程序错误的常用手段之一。不同等级的日志输出,代表不同的错误级别,有一些仅仅是警告,对程序运行无任何影响,则只需要打印出来即可;但有一些是严重的错误,会对后续程序的运行影响很大,除了打印信息外,最好还能直接断言,提示开发人员。
程序实际运行时,一般错误日志都是写到日志文件中;而开发环境下,直接打印到控制台更方便查看。想要实现这个功能,用宏来控制再方便不过。
开发环境visual studio 2013, 代码如下:
#include <iostream> #include <assert.h> #ifdef _DEBUG #define LOG_I(x) std::cout << "警告:" << x << std::endl #define LOG_E(x) std::cout << "错误:" << x << std::endl; assert(false) #else //有关文件的操作省略 #endif int _tmain(int argc, _TCHAR* argv[]) { LOG_I("有瑕疵"); LOG_E("有错误"); system("pause"); return 0; }
这里很简单,如果定义了_DEBUG宏,即开发调试环境,则将日志打印到控制台;否则,将日志写到对应文件中(简单起见,此处省略)。注意,宏定义最后面是没有分号的。
编译运行,结果如下:
LOG_E宏除了打印错误日志外,还会触发断言,这里这样使用没任何问题。
但是,日志的打印,一般都会有条件判断,即某错误条件成立后,才打印日志。代码调整如下:
#include <iostream> #include <assert.h> #ifdef _DEBUG #define LOG_I(x) std::cout << "警告:" << x << std::endl #define LOG_E(x) std::cout << "错误:" << x << std::endl; assert(false) #else //有关文件的操作省略 #endif int _tmain(int argc, _TCHAR* argv[]) { int iValue; std::cout << "请输入一个偶数:"; std::cin >> iValue; if (iValue % 2 == 0) LOG_I("数据正确"); else LOG_E("数据错误"); system("pause"); return 0; }
运行,输入1,结果如下:
和预想的一致,似乎没什么问题。但是如果输入的2,什么情况呢?
纳尼?发生了什么?
仔细看代码,用具体代码替换掉宏,if语句的代码就是如下:
问题就出在LOG_E宏上,里面有多条语句。展开后,只有第一条语句在else作用域内,第二条则一定会指定。
想要解决该怎么办?有两种方式:
1、在条件判断语句后面加上{}
调整后的代码如下:
#include <iostream> #include <assert.h> #ifdef _DEBUG #define LOG_I(x) std::cout << "警告:" << x << std::endl #define LOG_E(x) std::cout << "错误:" << x << std::endl; assert(false) #else //有关文件的操作省略 #endif int _tmain(int argc, _TCHAR* argv[]) { int iValue; std::cout << "请输入一个偶数:"; std::cin >> iValue; if (iValue % 2 == 0) { LOG_I("数据正确"); } else { LOG_E("数据错误"); } system("pause"); return 0; }
运行后结果如下:
结果正确!
但如果你是宏的设计者,则需要为你设计的宏负责,用下面的方式更合适。
2、多条语句的宏,用{}将多条语句括起来
修改代码如下:
#include <iostream> #include <assert.h> #ifdef _DEBUG #define LOG_I(x) std::cout << "警告:" << x << std::endl #define LOG_E(x) { std::cout << "错误:" << x << std::endl; assert(false); } #else //有关文件的操作省略 #endif int _tmain(int argc, _TCHAR* argv[]) { int iValue; std::cout << "请输入一个偶数:"; std::cin >> iValue; if (iValue % 2 == 0) LOG_I("数据正确"); else LOG_E("数据错误"); system("pause"); return 0; }
执行结果如下:
没问题!
有关宏的使用,一定要谨慎,特别是和条件判断语句搭配使用。
宏后面是否有";"也需要注意,和条件语句一起,也可能产生意想不到的问题。
-
rar压缩软件.rar
2016-02-13 10:52:44等写到日志文件中。读取开关 -ilog 描述获得更多信息。 固实压缩的文件列表 - rarfiles.lst ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ rarfiles.lst 包含一个用户定义的文件列表,告诉 RAR 添加文件到固实压缩文件... -
WinRAR_4.0.exe
2011-02-04 11:34:33等写到日志文件中。读取开关 -ilog 描述获得更多信息。 固实压缩的文件列表 - rarfiles.lst rarfiles.lst 包含一个用户定义的文件列表,告诉 RAR 添加文件到固实压缩文件时的顺 序。它可以包含文件名通配符... -
中文简体压缩软件RAR 6.0
2006-02-28 10:01:02当你需要发送一个文件到标准输出设备时,这也许很重要。 r 修复压缩文件。压缩文件修复是在两阶段中完成的。首先,在损坏的压缩 文件中查找恢复记录(参照'rr'命令)。如果压缩文件包含恢复记录,并且 损坏... -
WINRAR5.0正式注册版
2013-10-10 10:14:03文件名能在日志文件中正确存储。WinRAR 会自动删除非 Unicode 格式的旧 rar.log 文件来避免同一日志文件中混合不同的编码。控制台 RAR 的情况下,你需要手动删除 旧的 rar.log,否则 RAR 会在现有的 rar.log 后... -
Windows 系统错误代码简单分析
2010-04-14 11:21:57可能是一个包含注册表数据文件的结构已损坏,也可能内存中该文件的系统映像已损坏,或者因为备份副本(或日志)不存在(或损坏)导致无法恢复该文件。 1016 由注册表引起的 I/O 操作发生了不可恢复的错误。... -
McAfee 8.0 简体中文
2006-02-16 11:06:30- 日志文件格式 - Lotus Notes - 镜像任务 - 扫描 - 有害程序策略 - 文档 - 参与 McAfee 测试程序的测试 - 联系信息 - 版权和商标归属 - 许可和专利信息 _________________________________... -
电脑蓝屏对照码
2019-05-05 14:16:40有时保卫科可以顺利的查到是哪个生产小组的问题, 会在第一部分明确报告是哪个文件犯的错, 但常常它也只能查个大概范围, 而无法明确指明问题所在. 由于工厂全面被迫停止, 只有重新整顿开工, 有时, 那个生产小组会意识... -
winrar3.7 Beta8
2007-07-07 00:17:02<br> 到处的设置文件 settings.reg 默认也被保存到 %APPDATA%\WinRAR 文件夹中, 但是 也可以在“保存 WinRAR 设置”和 “加载 WinRAR 设置” 对话框中选择其他的文件 夹。 <br> WinRAR 在它的 ... -
-
WIN XP蓝屏代码大全
2013-08-08 12:29:21有时保卫科可以顺利的查到是哪个生产小组的问题, 会在第一部分明确报告是哪个文件犯的错, 但常常它也只能查个大概范围, 而无法明确指明问题所在. 由于工厂全面被迫停止, 只有重新整顿开工, 有时, 那个生产小组会意识... -
电脑问题大搜捕
2011-11-01 10:01:37协调器) 相关的文件, 分布式事务协调器可用于控制不同程序或进程间的的事务输出 和 消息传递. 可以删除) 24)mui(包含了多国语言用户界面的相关文件.可以删除) 25)npp(包含了一些用于在网络监视服务器上... -
-
-
如果你不会配置表单组默认选项配置,请先配置好user信息之后本地执行generate.py,根据提示信息手动输入,然后将分割线下的内容复制到配置文件中对应位置 如果问题中有省市县三级联动的位置,按xx省/xx市/xx县这个...
-
在命令行输入,gradlew compileDebugSources,可以查看打印报错的信息,这句话可以控制台输出代码报错的日志。 IOException: CreateProcess error=2, 系统找不到指定的文件。 具体报错日志如下所示 ...
-
(重要)AIX command 使用总结.txt
2011-12-25 16:40:17<3> mount /dev/lvinformix /opt/informix //将设备mount到文件系统上 <4> chfs -A yes /dev/lvinformix //-A yes|no 修改所建文件系统的自动安装属性(Auto-Mount) ***********************************************... -
自己动手写操作系统(含源代码).part2
2010-10-18 19:47:45尤其是,当这本书在我预想的时间内没有完成的时候,当我遇到困难迟迟不能解决的时候,你总在一旁给我鼓励,在你那里,我从来都能感觉到一种温暖,我深知,如果没有你的支持,我无法坚持下来将书写完。谢谢你,这本书... -
自己动手写操作系统(含源代码).part1
2010-10-18 19:41:25尤其是,当这本书在我预想的时间内没有完成的时候,当我遇到困难迟迟不能解决的时候,你总在一旁给我鼓励,在你那里,我从来都能感觉到一种温暖,我深知,如果没有你的支持,我无法坚持下来将书写完。谢谢你,这本书... -
oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 连接字符串
2017-05-06 20:26:52说明:将sql*plus屏幕中的内容输出到指定的文件 用法:开始印刷->spool 文件名 结束印刷->spool off 列子: 文件内容 9. 显示宽度 (linesize) 说明:设置显示行的宽度,默认是80个字符 用法:set linesize 120 ... -
配置成 /*,可以请求到 controller中,但是跳转到jsp时会被拦截,不能渲染jsp视图,不使用,一般用于filter 3、配置SpringMVC核心配置文件 springmvc-servlet.xml 所以springmvc-servlet.xml <?xml version=...
-
C#编程经验技巧宝典
2008-06-01 08:59:33111 <br>0184 如何在ASP.NET中获取文件的扩展名 111 <br>0185 如何在ASP.NET中用URL在页面之间传值 112 <br>0186 如何使用IsPostBack实现ASP.NET页面加载 112 <br>0187 如何利用输出缓存技术缓存...