SpringBoot中日志详解(一)

参考官方日志文档链接1
参考官方日志文档链接2
http://www.51gjie.com/javaweb/1096.html

1.日志框架基本介绍

常见的日志框架:JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j...

  • JCL(Jakarta Commons Logging) :spring 底层所使用的日志框架
  • JUL(java.util.logging) :java提供的日志框架,是JDK在1.4版本中引入的Java原生日志框架
  • Jboss-logging :就是jboss提供的日志框架(hibernate)
  • log4j :Apache的一个开源项目,可以控制日志信息输送的目的地是控制台、文件、GUI组件等,可以控制每一条日志的输出格式,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。虽然已经停止维护了,但目前绝大部分企业都是用的log4j。
  • logback :是由 Log4j 的作者设计完成的,拥有更好的特性,用来取代 Log4j 的一个日志框架,是 SLF4j 的原生实现
  • log4j2:已经不仅仅是 Log4j 的一个升级版本了,它从头到尾都被重写了。由于使用了 LMAX Disruptor 技术(无锁异步),使得日志的吞吐量、性能比 log4j 1.x 提高 10 倍,并解决了一些死锁的 bug,而且配置更加简单灵活。
  • slf4j(Simple Logging Facade for Java ):简单的日志框架,也是logback ,log4j 的作者写的,主要是目前日志的抽象层
日志门面 (日志的抽象层) 日志实现
JCL(Jakarta Commons Logging)、SLF4j(Simple Logging Facade for Java)、jboss-logging Log4j 、JUL(java.util.logging)、Log4j2 、Logback

2.springboot日志框架选择

SpringBoot 默认选择的是 SLF4J + Logback 的组合,本篇文章讲解的是默认的日志
在实际项目中我们可以整合 Log4j2 来代替原来的 Logback(形成 SLF4J + Log4j2 组合)。采用 Log4j2 有如下几个优点:

  • 相比与其他的日志系统,log4j2 丢数据的情况少;
  • 采用 disruptor 技术,在多线程环境下,性能高于 logback 等 10 倍以上(无论在同步日志模式还是异步日志模式下,在所有日志框架中 log4j2 性能都是最佳的);
  • 利用 jdk1.5 并发的特性,减少了死锁的发生;

3.日志级别

trace<debug<info<warn<error<fatal
⚠️:Logback does not have a FATAL level. It is mapped to ERROR.(Logback没有FATAL级别,映射到ERROR)

//记录器
Logger logger = LoggerFactory.getLogger(getClass());
@Test
public void contextLoads() {
    //日志的级别;
    //由低到高   trace<debug<info<warn<error
    //可以调整输出的日志级别;日志就只会在这个级别以以后的高级别生效
    logger.trace("这是trace日志...");
    logger.debug("这是debug日志...");
    //SpringBoot默认给我们使用的是info级别的,没有指定级别的就用SpringBoot默认规定的级别;root级别(默认只有下面输出信息)
    logger.info("这是info日志...");
    logger.warn("这是warn日志...");
    logger.error("这是error日志...");
}

4.maven依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
依赖关系

5.控制台输出基本介绍

2019-03-05 10:57:51.112  INFO 45469 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/7.0.52
2019-03-05 10:57:51.253  INFO 45469 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-03-05 10:57:51.253  INFO 45469 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1358 ms
2019-03-05 10:57:51.698  INFO 45469 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]
2019-03-05 10:57:51.702  INFO 45469 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]

输出内容:
• 时间日期:精确到毫秒,易于排序
• 日志级别:ERROR, WARN, INFO, DEBUG ,TRACE
• 进程ID:图中45469
• 分隔符:--- 分隔符用于区分实际日志消息的开始
• 线程名:方括号括起来(在控制台输出时可能被截断,也就是展示不全)
• Logger名:通常使用源代码的类名(通常缩写)
• •日志消息

6.颜色配置

如果你的终端支持ANSI,彩色输出是用来帮助可读性。你可以设置spring.output.ansi.enabled来改变默认的自动检测(detect):设置值

  • ALWAYS
    开启彩色输出
  • DETECT
    尝试检测ANSI 颜色是否支持
  • NEVER
    关闭彩色输出

彩色编码使用%clr转换字配置,最简单的情势是根据日志级别进行色彩输出,例如:

%clr(%5p)

日志级别到颜色的映射:

Level Color
FATAL Red
ERROR Red
WARN Yellow
INFO Green
DEBUG Green
TRACE Green

你可以通过在转换器中提供选项来指定应当试用的色彩或风格。例如,为了使文本显示黄色:

%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){yellow}

支持的颜色:
• blue
• cyan
• faint
• green
• magenta
• red
• yellow

7.SpringBoot修改日志的默认配置

① 设置日志级别

logging.level设置日志级别,后面跟生效的区域,比如root表示整个项目,也可以设置为某个包下,也可以具体到某个类名(日志级别的值不区分大小写)

#日志的最低输出级别调整,设置在com.xx包下
logging.level.com.xx=trace
#root日志以WARN级别输出(让日志只输出warn及以上级别的信息)
logging.level.root=warn
#springframework.web日志以DEBUG级别输出
logging.level.org.springframework.web=DEBUG
#hibernate日志以ERROR级别输出
logging.level.org.hibernate=ERROR

② 日志路径

# logging.path=
# 不指定路径在当前项目下生成springboot.log日志
# 可以指定完整的路径;
# logging.file=/usr/xx/springboot.log

# 主要用这种形式
# 在当前磁盘的根路径下创建spring文件夹和里面的log文件夹;使用 spring.log 作为默认文件
logging.path=/spring/log

# 在控制台输出的日志的格式
logging.pattern.console=%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%n
# 指定文件中日志输出的格式
logging.pattern.file=%d{yyyy-MM-dd} === [%thread] === %-5level === %logger{50} ==== %msg%n
logging.file logging.path Example Description
(none) (none) 只在控制台输出
指定文件名 (none) my.log 输出日志到my.log文件(可以是绝对路径,也可以是相对路径)
(none) 指定目录 /var/log 输出到指定目录的 spring.log 文件中
指定文件名 指定目录 输出到文件名,前一个配置生效

当日志文件到达10Mb时会循环保存。文件的大小限制可通过logging.file.max-size属性设置。之前保存的日志文件会无限期存档,除非配置logging.file.max-history属性

③ 日志输出格式

%d:表示日期时间,
%thread:表示线程名,
%-5level:级别从左显示5个字符宽度,
%logger{50}:表示logger名字最长50个字符,否则按照句点分割。
%msg:日志消息,
%n:换行符

实例:%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n

8.自定义日志配置

① 配置文件名称

在xml文件中,指定日志文件

Logging System Customization
Logback logback-spring.xml, logback-spring.groovy, logback.xml, or logback.groovy
Log4j2 log4j2-spring.xml or log4j2.xml
JDK (Java Util Logging) logging.properties

建议将-spring变体用于日志记录配置(例如,logback-spring.xml而不是logback.xml)。如果使用标准配置位置,Spring将无法完全控制日志初始化
如果你既想完全掌控日志配置,但又不想用logback.xml作为Logback配置的名字,可以通过logging.config属性指定自定义的名字:

logging.config=classpath:logback-config.xml 
  • Spring Boot包含了许多可以帮助进行高级配置的Logback扩展,您可以在logback-spring.xml配置文件中使用这些扩展名
  • 由于标准的logback.xml配置文件加载的太早,所以你不能在里面使用扩展部分,您需要使用logback-spring.xml或定义一个logging.config属性

② springProfile标签针对不同开发环境

使用<springProfile>标签,您可以根据活动的Spring配置文件选择包括或排除配置部分

<springProfile name="staging">
    <!-- configuration to be enabled when the "staging" profile is active -->
</springProfile>

<springProfile name="dev | staging">
    <!-- configuration to be enabled when the "dev" or "staging" profiles are active -->
</springProfile>

<springProfile name="!production">
    <!-- configuration to be enabled when the "production" profile is not active -->
</springProfile>

③ Environment Properties

该<springProperty>标签允许您公开来自Spring环境的属性,以便在Logback中使用。如果要从application.properties中访问文件中的值,这样做很有用。该标签的工作方式与Logback的<property>标签类似。但是,不是指定直接的值value,而是指定属性的源source(来自Environment)。如果需要将该属性存储在局部作用域之外的其他地方,则可以使用scope属性。如果需要回退值(在Environment中没有设置该属性的情况下),可以使用defaultValue属性。以下示例显示如何公开用于Logback的属性

<springProperty scope="context" name="fluentHost" source="myapp.fluentd.host"
        defaultValue="localhost"/>
<appender name="FLUENT" class="ch.qos.logback.more.appenders.DataFluentAppender">
    <remoteHost>${fluentHost}</remoteHost>
    ...
</appender>

④ 配置详解

<?xml version="1.0" encoding="UTF-8"?>
<!--
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration  scan="true" scanPeriod="60 seconds" debug="false">
    <!--每个logger都关联到logger上下文,默认上下文名称为“default”。但可以使用设置成其他名字,用于区分不同应用程序的记录。一旦设置,不能修改,可以通过%contextName来打印日志上下文名称 -->
    <contextName>logback</contextName>
    <!--property:用来定义变量值的标签, 有两个属性,name和value;其中name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量-->
    <property name="LOG_PATH" value="/usr/xx/log.log" />
    <!--从配置文件中读取logging.path属性值-->
    <springProperty name="LOG_HOME" source="logging.path"/>

    <!--在pattern中直接用${pattern_format}调用公共部分-->
    <property name="pattern_format" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{50} - %msg%n" />

    <!-- <appender>:用来格式化日志输出节点,有两个属性name和class,class用来指定哪种输出策略,常用就是控制台输出策略和文件输出策略。-->

    <!--输出到控制台 ConsoleAppender -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!--ThresholdFilter为系统定义的拦截器,此日志appender是为开发使用,只配置最低级别,此配置表示控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
        <!--设置输出格式 class可省略-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{50} - %msg%n</pattern>
            <!--配置颜色,可使用下面-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %blue(%logger{50}) - %highlight(%msg) %n</pattern>
            <!--设置编码,可省略-->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!--输出到文件,时间窗口滚动-->
    <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--日志名,指定最新的文件名,其他文件名使用FileNamePattern -->
        <File>${LOG_PATH}/info.log</File>
        <!--文件滚动模式-->
        <!--第一种-->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名,可设置文件类型为gz,开启文件压缩,初始i为0-->
            <FileNamePattern>${LOG_PATH}/info.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <!--日志文件保留天数,也就是过期时间-->
            <MaxHistory>15</MaxHistory>
            <!--单个日志文件最大值,达到之后就进行切割-->
            <maxFileSize>10MB</maxFileSize>
            <!--日志文件总体的最大值,达到之后,就会删除旧的日志-->
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>

       <!--关系:SizeAndTimeBasedRollingPolicy extends TimeBasedRollingPolicy-->
       <!--第二种,因TimeBasedRollingPolicy下没有maxFileSize,像上面那样配置后会报错-->
       <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${LOG_PATH}/info.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <MaxHistory>15</MaxHistory>
            <totalSizeCap>1GB</totalSizeCap>

            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>

        <!--
             上面配置意思:每天产生一个日志文件,如果超出了10M,日志就进行切割,并且在日志文件名称上加一,新的日志存入新的i++文件中;
             日志文件最多保持15天,日志文件总共最大为1G;
             当超过1G时候,删除旧的日志文件,在我测试时候发现,如果某天的日志文件分割了,会先删除i=1的,再删除i=0,接着i=2,3....
        -->

        <!--输出格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <!--设置编码,可省略-->
            <charset>UTF-8</charset>
        </encoder>

        <!-- 过滤器,过滤掉不是指定日志水平的日志,精确定位 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- 设置日志级别 -->
            <level>INFO</level>
            <!-- 如果跟该日志水平相匹配,则接受 -->
            <onMatch>ACCEPT</onMatch>
            <!-- 如果跟该日志水平不匹配,则过滤掉 -->
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    
    <!-- 指定主日志输出级别,只有一个level属性-->
    <root level="info">
        <appender-ref ref="console" />
        <appender-ref ref="file" />
    </root>
    
    <!--<loger>指定自定义日志的级别,有name,level,addtivity属性-->
    <!-- logback为java中的包 -->
    <logger name="com.xx.controller"/>
    <!--
    name:用来指定受此loger约束的某一个包或者具体的某一个类。
    level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,还        有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。如果未设置此属性,那么当前loger将会继承上级的级别。
    addtivity:是否向上级loger传递打印信息。默认是true。
    -->
    <logger name="com.xx.controller.SpringController" level="WARN" additivity="false">
        <appender-ref ref="console"/>
    </logger>
</configuration> 

root 指定的日志级别就是用类进行输出的日志,例如:

private static Logger log = LoggerFactory.getLogger(logbackTest.class);

⑤ loger的使用:

public class TestController {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @GetMapping("/show")
    public void show() {
        logger.trace("这是trace日志...");
        logger.debug("这是debug日志...");
        logger.info("这是info日志...");
        logger.warn("这是warn日志...");
        logger.error("这是error日志...");
    }
}
<root level="info">
    <appender-ref ref="console" />
</root>
  • 第一种:带有loger的配置,不指定级别,不指定appender
<logger name="com.mine.demo"/>
将控制demo包下的所有类的日志的打印,但是并没用设置打印级别,所以继承他的上级的日志级别,即root的级别“info”;
没有设置addtivity,默认为true,将此loger的打印信息向上级传递,设置为false时候,执行/show,show()方法执行,但是不打印日志信息;
没有设置appender,此loger本身不打印任何信息。
当执行该包下的某个类中的功能时,将方法内所有日志信息传递给root,本身并不打印;
root接到下级传递的信息,交给已经配置好的名为“console”的appender处理,“console”appender将信息打印到控制台。

此配置类似:<logger name="com.mine.demo.TestDemoController" level="info" additivity="true">

结果:
2020-10-09 15:03:57.680 logback [http-nio-8080-exec-1] INFO  com.mine.demo.TestDemoController - 这是info日志...
2020-10-09 15:03:57.680 logback [http-nio-8080-exec-1] WARN  com.mine.demo.TestDemoController - 这是warn日志...
2020-10-09 15:03:57.681 logback [http-nio-8080-exec-1] ERROR com.mine.demo.TestDemoController - 这是error日志...

当additivity=false时候,本身打印,但是没有设置appender,此loger本身不打印任何信息。
  • 第二种:带有多个loger的配置,指定级别,指定appender
<logger name="com.mine.demo.TestDemoController" level="WARN" additivity="false">
    <appender-ref ref="console"/>
</logger>
控制com.mine.demo.TestDemoController类的日志打印,打印级别为“WARN”;
additivity属性为false,表示此loger的打印信息不再向上级传递;
指定了名字为“console”的appender;
当执行TestDemoController中的方法时将级别为“WARN”及大于“WARN”的日志信息交给此loger指定的名为“console”的appender处理,在控制台中打出日志,不再向上级root传递打印信息。

结果:
2020-10-09 14:42:19.792 logback [http-nio-8080-exec-1] WARN  com.mine.demo.TestDemoController - 这是warn日志...
2020-10-09 14:42:19.792 logback [http-nio-8080-exec-1] ERROR com.mine.demo.TestDemoController - 这是error日志...

<logger name="com.mine.demo.TestDemoController" level="warn" additivity="true">
    <appender-ref ref="console"/>
</logger>
<logger name="com.mine.demo.TestDemoController" level="info" additivity="false"/>
多个个同时存在时候,后一个覆盖前一个,level,additivity,appender后一个有则覆盖,没有则使用前一个配置,所以上面的level="debug", additivity="false", <appender-ref ref="console"/>

结果:
2020-10-09 15:03:57.680 logback [http-nio-8080-exec-1] INFO  com.mine.demo.TestDemoController - 这是info日志...
2020-10-09 15:03:57.680 logback [http-nio-8080-exec-1] WARN  com.mine.demo.TestDemoController - 这是warn日志...
2020-10-09 15:03:57.681 logback [http-nio-8080-exec-1] ERROR com.mine.demo.TestDemoController - 这是error日志...

<root level="warn">
    <appender-ref ref="console" />
</root>
<logger name="com.mine.demo.TestDemoController" level="info" additivity="false">
    <appender-ref ref="console"/>
</logger>
结果:
2020-10-09 15:30:12.696 logback [http-nio-8080-exec-1] INFO  com.mine.demo.TestDemoController - 这是info日志...
2020-10-09 15:30:12.696 logback [http-nio-8080-exec-1] INFO  com.mine.demo.TestDemoController - 这是info日志...
2020-10-09 15:30:12.698 logback [http-nio-8080-exec-1] WARN  com.mine.demo.TestDemoController - 这是warn日志...
2020-10-09 15:30:12.698 logback [http-nio-8080-exec-1] WARN  com.mine.demo.TestDemoController - 这是warn日志...
2020-10-09 15:30:12.698 logback [http-nio-8080-exec-1] ERROR com.mine.demo.TestDemoController - 这是error日志...
2020-10-09 15:30:12.698 logback [http-nio-8080-exec-1] ERROR com.mine.demo.TestDemoController - 这是error日志...

开始理解的时候是本身打印info级别,向上级root传递的时候,上级是warn级别的,所以打印是本身打印info级别以上的,上级只打印筛选的warn级别以上的。结果多次测试发现不是这样。
后来理解:当本身的打印日志信息传递给上级,上级只负责输出。所以当本身打印info日志,向上级root传递info信息,上级继续打印info日志;打印warn日志......依次类推

9.最终配置logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <!-- 存放日志文件的路径的根目录 -->
    <springProperty name="log_path" source="custom.logging.path"/>

    <!--输出到控制台 ConsoleAppender -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
        <!--设置输出格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!--文件输出,时间窗口滚动-->
    <appender name="info" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${log_path}/info.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <MaxHistory>15</MaxHistory>
            <maxFileSize>10MB</maxFileSize>
            <totalSizeCap>2GB</totalSizeCap>
        </rollingPolicy>

        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log_path}/error.log</file>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log_path}/error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>15</maxHistory>
            <totalSizeCap>2GB</totalSizeCap>
        </rollingPolicy>
        <!-- 此日志文档只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <springProfile name="dev">
        <root level="info">
            <appender-ref ref="console"/>
        </root>
        <logger name="com.xx.dao" level="debug" />
    </springProfile>

    <springProfile name="test,prod">
        <root level="info">
            <appender-ref ref="console"/>
            <appender-ref ref="info"/>
            <appender-ref ref="error"/>
        </root>
    </springProfile>
</configuration>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343