008_logback配置语法
1. 配置文件的基本结构
1.1. Logback配置文件的语法非常灵活。正因为灵活, 所以无法用DTD或XML schema进行定义。尽管如此, 可以这样描述配置文件的基本结构: 以<configuration>开头, 后面有零个或多个<appender>元素, 有零个或多个<logger>元素, 有最多一个<root>元素。
2. 配置logger或<logger>元素
2.1. Logger是用<logger>元素配置的。<logger>元素有且仅有一个name属性、一个可选的level属性和一个可选的additivity属性。Level属性的值大小写无关, 其值为: TRACE、DEBUG、INFO、 WARN、ERROR、ALL和OFF中的一个值。还可以是一个特殊的字符串"INHERITED"或其同义词"NULL", 表示强制继承上级的级别。
2.2. <logger>元素可以包含零个或多个<appender-ref>元素, 表示这个appender会被添加到该logger。强调一下, 每个用<logger>元素声明的logger, 首先会移除所有的appender, 然后添加引用的appender, 所以如果logger没有引用任何appender, 就会失去所有appender。
2.3. 例子
2.3.1. 新建一个名为LogbackCfgGrammer的Java项目, 同时添加相关jar包
2.3.2. 编辑LoggerCfg.java
package com.zr.cfg;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;public class LoggerCfg {private static final Logger logger = LoggerFactory.getLogger(LoggerCfg.class);public static void main(String[] args) {// 上下文LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();// Joran配置文件处理类JoranConfigurator cfg = new JoranConfigurator();cfg.setContext(lc);// 上下文已经读取配置文件或使用默认配置文件, 这里进行重置操作。lc.reset();try {cfg.doConfigure("cfg/logger.xml");} catch (JoranException e) {e.printStackTrace();}logger.info("配置logger或<logger>元素");logger.debug("配置logger或<logger>元素");}
}
2.3.3. 新建cfg文件夹, 在该文件夹下编辑logger.xml
<configuration><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <encoder charset="UTF-8"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <logger name="com.zr.cfg.LoggerCfg" level="info"><appender-ref ref="stdout" /></logger></configuration>
2.3.4. 只会打印info和高于info级别的日志
3. 配置根logger或<root>元素
3.1. <root>元素配置根logger。该元素有一个level属性。没有name属性, 因为已经被命名为"ROOT"。Level属性的值大小写无关, 其值为: TRACE、DEBUG、INFO、 WARN、ERROR、ALL和OFF中的一个值。注意不能设置为"INHERITED"或"NULL"。
3.2. <logger>元素可以包含零个或多个<appender-ref>元素。与<logger>元素类似, 声明<root>元素后, 会先关闭然后移除全部当前appender, 只引用声明的appender。如果root元素没有引用任何appender, 就会失去所有appender。
3.3. 基本选择规则依赖于被调用的logger的有效级别, 而不是appender所关联的logger的级别。Logback首先判断记录语句是否被启用, 如果启用, 则调用logger等级里的appender, 同时如果有继承的话, 还会调用祖先的appender, 无视logger的级别。
3.4. 例子
3.4.1. 编辑RootLoggerCfg.java
package com.zr.cfg;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;public class RootLoggerCfg {private static final Logger logger = LoggerFactory.getLogger(RootLoggerCfg.class);public static void main(String[] args) {// 上下文LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();// Joran配置文件处理类JoranConfigurator cfg = new JoranConfigurator();cfg.setContext(lc);// 上下文已经读取配置文件或使用默认配置文件, 这里进行重置操作。lc.reset();try {cfg.doConfigure("cfg/rootlogger.xml");} catch (JoranException e) {e.printStackTrace();}logger.info("配置根logger或<root>元素");logger.debug("配置根logger或<root>元素");}
}
3.4.2. 在cfg文件夹下编辑rootlogger.xml
<configuration><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <encoder charset="UTF-8"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <logger name="com.zr.cfg.RootLoggerCfg" level="info"></logger><root level="off"><appender-ref ref="stdout" /></root>
</configuration>
3.4.3. 各个logger的级别
3.4.4. 配置里唯一的appender"stdout", 被关联到级别为OFF的根logger, 根logger的级别不起任何作用。com.zr.cfg.RootLoggerCfg类的INFO级别是启用的, 因此会输出com.zr.cfg.RootLoggerCfg类INFO级别及其更高级别的日志:
4. 配置Appender
4.1. Appender用<appender>元素配置, 该元素必要属性name和class。name属性指定appender的名称, class属性指定appender类的全限定名。
4.2. <appender>元素可以包含零个或一个<layout>元素或者零个或一个<encoder>元素和零个或多个<filter>元素。除了这三个常用元素之外, 还可以包含任意数量的javabean属性。
4.3. 下图演示了常用结构, 注意对javabean属性的支持在图中不可见。
4.4. <layout>元素的class属性是必要的, 表示将被实例化的layout类的全限定名。因为太常用了, 所以当layout是PatternLayout 时, 可以省略class属性。
4.5. <encoder>元素class属性是必要的, 表示将被实例化的encoder类的全限定名。因为太常用了, 所以当encoder是PatternLayoutEncoder时, 可以省略class属性。
4.6. 记录输出到多个appender很简单, 先定义各种appender, 然后在logger里进行引用就行了。
4.7. 注意每个appender都有自己的encoder。Encoder通常不能被多个appender共享, layout也是。
4.8. 例子
4.8.1. 编辑AppenderCfg.java
package com.zr.cfg;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;public class AppenderCfg {private static final Logger logger = LoggerFactory.getLogger(AppenderCfg.class);public static void main(String[] args) {// 上下文LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();// Joran配置文件处理类JoranConfigurator cfg = new JoranConfigurator();cfg.setContext(lc);// 上下文已经读取配置文件或使用默认配置文件, 这里进行重置操作。lc.reset();try {cfg.doConfigure("cfg/appender.xml");} catch (JoranException e) {e.printStackTrace();}logger.info("Appender用<appender>元素配置, 该元素必要属性name和class。");logger.debug("name属性指定appender的名称, class属性指定appender类的全限定名。");}
}
4.8.2. 在cfg文件夹下编辑appender.xml
<configuration><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><layout class="ch.qos.logback.classic.PatternLayout"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></layout></appender><appender name="file" class="ch.qos.logback.core.FileAppender"><file>log/my.log</file><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><root level="debug"><appender-ref ref="file" /><appender-ref ref="stdout" /></root></configuration>
4.8.3. 运行结果
4.9. Appender累积
4.9.1. 默认情况下, appender是可累积的: logger会把记录输出到它自身的appender和它所有祖先的appender。因此, 把同一appender关联到多个logger会导致重复输出。
4.9.2. Appender的叠加性对新手来说并不是陷阱, 反而是非常方便的。举例来说, 你可以让某些系统里所有logger的记录信息出现在控制台, 却让某些特定logger的记录信息发到一个特定的appender。
<configuration><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><layout class="ch.qos.logback.classic.PatternLayout"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></layout></appender><appender name="file" class="ch.qos.logback.core.FileAppender"><file>log/error.log</file><append>false</append><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><logger name="com.zr.cfg.AccumulateCfg" level="error"><appender-ref ref="file" /></logger><root><appender-ref ref="stdout" /></root></configuration>
4.9.3. 如果你觉得默认的累积行为不合适, 可以设置叠加性标识为false以关闭它。这样的话, logger树里的某个分支可以输出到与其他logger不同的appender。
<configuration><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><layout class="ch.qos.logback.classic.PatternLayout"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></layout></appender><appender name="file" class="ch.qos.logback.core.FileAppender"><file>log/error.log</file><append>false</append><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><logger name="com.zr.cfg.AccumulateCfg" level="error" additivity="false"><appender-ref ref="file" /></logger><root><appender-ref ref="stdout" /></root></configuration>
4.9.4. 创建AccumulateCfg.java
package com.zr.cfg;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;public class AccumulateCfg {private static final Logger logger = LoggerFactory.getLogger(AccumulateCfg.class);private static final Logger root = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);public static void main(String[] args) {// 上下文LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();// Joran配置文件处理类JoranConfigurator cfg = new JoranConfigurator();cfg.setContext(lc);// 上下文已经读取配置文件或使用默认配置文件, 这里进行重置操作。lc.reset();try {cfg.doConfigure("cfg/accumulate.xml");} catch (JoranException e) {e.printStackTrace();}logger.error("默认情况下, appender是可累积的: logger会把记录输出到它自身的appender和它所有祖先的appender。");logger.error("因此, 把同一appender关联到多个logger会导致重复输出。");logger.error("Appender的叠加性对新手来说并不是陷阱, 反而是非常方便的。");root.warn("举例来说, 你可以让某些系统里所有logger的记录信息出现在控制台, 却让某些特定logger的记录信息发到一个特定的appender。");root.info("如果你觉得默认的累积行为不合适, 可以设置叠加性标识为false以关闭它。");root.debug("这样的话, logger树里的某个分支可以输出到与其他logger不同的appender。");}
}
4.9.5. 创建accumulate.xml, 使用步骤4.9.2.的配置文件
4.9.6. 运行AccumulateCfg.java
4.9.7. 修改accumulate.xml配置, 使用步骤4.9.3.的配置文件, 再次运行AccumulateCfg.java
5. 设置上下文名称
5.1. 每个logger都关联到logger上下文。默认情况下, logger上下文名为"default"。但是你可以借助配置指令<contextName>设置成其他名字。注意一旦设置logger上下文名称后, 不能再改。设置上下文名称后, 可以方便地区分来自不同应用程序的记录。
5.2. 例子
5.2.1. 编辑ContextName.java
package com.zr.cfg;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;public class ContextName {private static final Logger logger = LoggerFactory.getLogger(ContextName.class);public static void main(String[] args) {// 上下文LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();// Joran配置文件处理类JoranConfigurator cfg = new JoranConfigurator();cfg.setContext(lc);// 上下文已经读取配置文件或使用默认配置文件, 这里进行重置操作。lc.reset();try {cfg.doConfigure("cfg/contextName.xml");} catch (JoranException e) {e.printStackTrace();}logger.info("每个logger都关联到logger上下文。");logger.debug("你可以借助配置指令<contextName>设置上下文名字。");}
}
5.2.2. 在cfg文件夹下编辑contextName.xml
<configuration debug="true"><contextName>日志服务器</contextName><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <encoder charset="UTF-8"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <root><appender-ref ref="stdout" /></root>
</configuration>
5.2.3. 运行结果
6. 变量替换
6.1. 原则上, 指定变量的地方就能够发生变量替换。变量替换的语法与Unix shell中的变量替换相似。位于"${"与"}"之间的字符串是键(key), 取代键的值可以在同一配置文件里指定, 也可以在外部文件或通过系统属性进行指定。
6.2. 属性被插入logger上下文
6.2.1. 注意通过<property>元素定义的值实际上会被插入logger上下文。换句话说, 这些值变成了logger上下文的属性。所以, 它们对所有记录事件都可用, 包括通过序列化方式被发送到远程主机的记录事件。
6.2.2. 下面的例子在配置文件的开头声明了一个变量又名替换属性, 它代表输出文件的位置, 然后在后面的配置文件里使用它。
<property name="fileName" value="my.log" />
6.3. 属性文件
6.3.1. 当需要很多变量时, 更方便的做法是在一个单独的文件里声明所有变量。
<property file="variables.properties" />
6.3.2. 还可以不引用文件, 而是引用class path上的资源。
<property resource="variables.properties" />
6.3.3. variables.properties文件内容类似于:
pathPre=/log
fileName=my.log
fullPath=/log/my.log
6.4. 嵌套变量替换
6.4.1. Logback支持嵌套变量替换。这里的嵌套是指变量的值里包含对其他变量的引用。
pathPre=/log
fileName=my.log
fullPath=${pathPre}/${fileName}
6.5. 变量的默认替换值
6.5.1. 在某些特定情况下, 最好给变量一个默认值, 以免变量未被声明或值为null。Bash shell用":-"指定默认值。例如, 假设"appName"未被声明, 那么"${appName:-zrApp}"将被解释为"zrApp"。
6.6. Logback自动定义了一个常用变量"${HOSTNAME}"。
7. 配置文件里的条件化处理
7.1. 开发者经常需要针对不同的环境在不同的配置文件里换来换去, 比如开发、测试和生产环境。这些配置文件大同小异。为避免重复劳动, logback支持在配置文件里进行条件化处理, 用<if>、<then>和<else>这些元素可以让一个配置文件适用于多个环境。
7.2. 条件语句一般格式如下
<configuration> <!-- if-then form --> <if condition="some conditional expression"> <then> ... </then> </if> <!-- if-then-else form --> <if condition="some conditional expression"> <then> ... </then> <else> ... </else> </if> </configuration
7.3. 其中"condition"是java表达式, 只允许访问上下文属性和系统属性。对于作为参数传入的键, property()方法或其等价的p()方法将返回属性的字符串值。例如, 想访问属性键为"k"的值, 你可以用property("k")或等价的 p("k")。如果键为"k"的属性未被定义, property方法将返回空字符串而不是null, 这样避免了检查null值。
7.4. 例子
7.4.1. 条件语句需要两个额外的包commons-compiler-3.1.3.jar和janino-3.1.3.jar
7.4.2. 编辑Condition.java
package com.zr.cfg;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;public class Condition {private static final Logger logger = LoggerFactory.getLogger(Condition.class);public static void main(String[] args) {// 上下文LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();// Joran配置文件处理类JoranConfigurator cfg = new JoranConfigurator();cfg.setContext(lc);// 上下文已经读取配置文件或使用默认配置文件, 这里进行重置操作。lc.reset();try {cfg.doConfigure("cfg/condition.xml");} catch (JoranException e) {e.printStackTrace();}logger.error("错误信息");logger.warn("警告信息");logger.info("信息");logger.debug("测试信息");}
}
7.4.3. 在cfg文件夹下编辑condition.xml
<configuration><property name="development" value="dev" /><contextName>${pathPre:-zrApp}</contextName><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <encoder charset="UTF-8"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <if condition='p("development").contains("test")'> <then> <root level="debug"><appender-ref ref="stdout" /></root></then><else> <root level="warn"><appender-ref ref="stdout" /></root></else></if>
</configuration>
7.4.4. 运行结果
8. 从JNDI获取变量
8.1. 在某些特定情况下, 你也许利用JNDI里存储的env项, <insertFromJNDI>指令会从JNDI里取得env项, 然后用as属性把它们作为变量。
8.2. 新建一个名为JNDIGetVariable的动态Web工程, 同时添加相关jar包
8.3. 创建JNDIAction.java
package com.fj;import java.io.IOException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class JNDIAction extends HttpServlet {private static final long serialVersionUID = 1L;private static final Logger logger = LoggerFactory.getLogger(JNDIAction.class);@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {try {InitialContext ctx = new InitialContext();String contextName = (String) ctx.lookup("java:comp/env/logback/context-name");logger.error("从JNDI获取变量: {}", contextName);} catch (NamingException e) {e.printStackTrace();}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}
8.4. 在src目录下添加logback.xml
<configuration><insertFromJNDI env-entry-name="java:comp/env/logback/context-name" as="context-name" /><contextName>${context-name}</contextName><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%contextName %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><root level="debug"><appender-ref ref="stdout" /></root></configuration>
8.5. 配置web.xml
8.6. 运行项目
9. 文件包含
9.1. Joran支持在配置文件里包含其他文件。方法是声明<include>元素, 被包含的内容可以是文件、资源或URL。
9.2. 作为文件, 用"file"属性包含一个文件。可以用相对路径, 但是需要注意, 当前目录是由应用程序决定的, 与配置文件的路径必要的联系。
<include file="includedConfig.xml" />
9.3. 作为资源, 用"resource"属性包含一个资源, 也就是在class path上的文件。
<include resource="includedConfig.xml" />
9.4. 作为URL, 用"url"属性包括一个URL。
<include url="http://some.host.com/includedConfig.xml" />
9.5. 被包含的文件必须把它的元素嵌套在<included>元素里。请注意<included>元素是必需的。
9.6. 例子
9.6.1. 编辑IncludeCfg.java
package com.zr.cfg;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;public class IncludeCfg {private static final Logger logger = LoggerFactory.getLogger(IncludeCfg.class);public static void main(String[] args) {// 上下文LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();// Joran配置文件处理类JoranConfigurator cfg = new JoranConfigurator();cfg.setContext(lc);// 上下文已经读取配置文件或使用默认配置文件, 这里进行重置操作。lc.reset();try {cfg.doConfigure("cfg/containingcfg.xml");} catch (JoranException e) {e.printStackTrace();}logger.error("错误信息");logger.warn("警告信息");logger.info("信息");logger.debug("测试信息");}
}
9.6.2. 在cfg文件夹下编辑containingcfg.xml
<included><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <encoder charset="UTF-8"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender>
</included>
9.6.3. 在cfg文件夹下编辑includecfg.xml
<configuration><include file="cfg/includecfg.xml"></include><root><appender-ref ref="stdout" /></root>
</configuration>
9.6.4. 运行结果
008_logback配置语法相关推荐
- Highcharts 配置语法;Highcharts 配置选项详细说明
Highcharts 配置语法 本章节我们将为大家介绍使用 Highcharts 生成图表的一些配置. 第一步:创建 HTML 页面 创建一个 HTML 页面,引入 jQuery 和 Highchar ...
- Git 中 .gitignore 的配置语法
一.前言 在日常的开发中,当我们需要将一个项目提交到 Git 时,并不是所有的文件都需要提交,比如一些自动生成的文件,类似于 .idea 文件.class 文件等,这时候就可以使用.gitignore ...
- Nginx——nginx作为静态资源web服务(配置语法)
目录 一.sendfile的配置语法(即文件读取的配置语法) 二.tcp_nopush的配置语法(即高传输效率的配置语法) 三.tcp_nodelay的配置语法(即实时性的配置语法) 四.gzip的配 ...
- 【转】Vczh Library++3.0之可配置语法分析器(前言)
从网上无意间看到这个系列的文章,作者非常有想法,转下来慢慢研究,好好学习. 祝大家学习愉快,做自己的爱好 ^_^ ! 花了差不多两个星期的时间将一个可配置语法分析器(Combinator)写好了.这个 ...
- C++轻量级可配置语法分析器(开源) - λ-calculus(惊愕到手了欧耶,GetBlogPostIds.aspx) - C++博客...
C++轻量级可配置语法分析器(开源) - λ-calculus(惊愕到手了欧耶,GetBlogPostIds.aspx) - C++博客 C++轻量级可配置语法分析器(开源) - λ-calculus ...
- syslog-ng详解——syslog-ng配置语法
在"运行syslog-ng"中我们简单介绍了一个基本配置文件的大概结构,保证syslog-ng能正常运行起来.这边将详细介绍下syslog-ng的日志配置及如何进行高效的配置,先介 ...
- 重识Nginx - 03 Nginx配置语法
文章目录 Nginx配置语法 配置参数: 时间的单位 配置参数: 空间的单位 http配置的指令块 Nginx配置语法 配置文件由指令与指令块构成 每条指令以;分号结尾,指令与参数间以空格符号分隔 指 ...
- 【转】Vczh Library++ 3.0之可配置语法分析器(设计文法表达式)
从网上无意间看到这个系列的文章,作者非常有想法,转下来慢慢研究,好好学习. 祝大家学习愉快,做自己的爱好 ^_^ ! 上一篇文章中我们看到了可配置语法分析器使用起来的样子,在这篇文章中我将告诉大家如何 ...
- linux下varnish4配置语法(基础)
varnish4 安装可以查看:http://php2012web.blog.51cto.com/5585213/1640182 VCL 说明文档:https://www.varnish-cache. ...
最新文章
- datatable如何生成级联数据_UE4 C++结合DataTable批量快速创建DataAsset
- 计算机控制水槽液位控制,计算机过程控制实验报告单容水箱液位数学模型的测定实验...
- 操作系统及编程语言历史以及shell命令
- 标签插入两一个html,一个类下有很多a标签,给第二个a标签添加样式,怎么写才能不用再给第二个a添加类_html/css_WEB-ITnose...
- 谷歌AI掌门人Jeff Dean获冯诺依曼奖;微软计划自研PC和服务器芯片;Ruby 3.0 RC1发布|极客头条...
- python安装csv出错_python处理csv文件问题解决贴
- mysql数据库在linux下的导出和导入及每天的备份
- 昂达v891w可以用u盘linux,拆机小能手——ONDA 昂达 V891w CH 双系统电脑国产平板 拆解清灰!...
- box-sizing: border-box的作用
- 京东商品如何批量修改?
- python代码画人物_Python绘制可爱的卡通人物 | 【turtle使用】
- 北京住房公积金联名卡查询使用
- 计算机购销存系统论文,企业进销存管理系统毕业论文.doc
- 缓解环境噪声对音频质量干扰
- 腾讯微服务框架 Tars 的 Go 性能提升之路
- Android开发——集成友盟社会化分享遇到的坑(一)
- 阿里云OSS服务使用操作流程
- java实现二维码生成的几个方法
- 简述计算机辅助船舶制造的技术特点,01234计算机辅助船舶制造.doc
- 强制加班下的员工状态