Logback浅析

原文地址:

http://www.cnblogs.com/yongze103/archive/2012/05/05/2484753.html


1、Logback为取代log4j而生

     Logback是由log4j创始人Ceki Gülcü设计的又一个开源日志组件。logback当前分成三个模块:logback-core,logback- classic和logback-access。

2、Logback的核心对象:Logger、Appender、Layout

     Logback主要建立于Logger、Appender 和 Layout 这三个类之上。

     Logger:日志的记录器,把它关联到应用的对应的context上后,主要用于存放日志对象,也可以定义日志类型、级别。Logger对象一般多定义为静态常量,如:


 1 package com.logs;
 2 
 3 import org.slf4j.Logger;
 4 import org.slf4j.LoggerFactory;
 5 
 6 public class MyApp {
 7     final static Logger logger = LoggerFactory.getLogger("MyApp.class");
 8     public static void main(String[] args) {
 9         
10         logger.trace("trace");
11         logger.debug("debug str");
12         logger.info("info str");
13         logger.warn("warn");
14         logger.error("error");
15     }
16 }

     Appender:用于指定日志输出的目的地,目的地可以是控制台、文件、远程套接字服务器、 MySQL、 PostreSQL、Oracle和其他数据库、 JMS和远程UNIX Syslog守护进程等。

     Layout:负责把事件转换成字符串,格式化的日志信息的输出。具体的Layout通配符,可以直接查看帮助文档。

3、Level 有效级别

    Logger可以被分配级别。级别包括:TRACE、DEBUG、INFO、WARN和ERROR,定义于ch.qos.logback.classic.Level类。程序会打印高于或等于所设置级别的日志,设置的日志等级越高,打印出来的日志就越少。如果设置级别为INFO,则优先级高于等于INFO级别(如:INFO、 WARN、ERROR)的日志信息将可以被输出,小于该级别的如DEBUG将不会被输出。为确保所有logger都能够最终继承一个级别,根logger总是有级别,默认情况下,这个级别是DEBUG。

4、 三值逻辑

   Logback的过滤器基于三值逻辑(ternary logic),允许把它们组装或成链,从而组成任意的复合过滤策略。过滤器很大程度上受到Linux的iptables启发。这里的所谓三值逻辑是说,过滤器的返回值只能是ACCEPT、DENY和NEUTRAL的其中一个。

如果返回DENY,那么记录事件立即被抛弃,不再经过剩余过滤器;

如果返回NEUTRAL,那么有序列表里的下一个过滤器会接着处理记录事件;

如果返回ACCEPT,那么记录事件被立即处理,不再经过剩余过滤器。

5、Filter 过滤器

    Logback-classic提供两种类型的过滤器:常规过滤器和TuroboFilter过滤器。Logback整体流程:Logger 产生日志信息;Layout修饰这条msg的显示格式;Filter过滤显示的内容;Appender具体的显示,即保存这日志信息的地方。

6、具体使用案例

     Java项目中一般都会应用比如struts、spring、hibernate等开源框架,而这些框架很多是应用log4j记录日志的,所以我们考虑用log4j +slf4j + logback 。这样我们需要导入log4j-over-slf4j-1.6.4.jar 、logback-classic-1.0.1.jar 、logback-core-1.0.1.jar 、slf4j-api-1.6.4.jar ,如果你要用到EvaluatorFilter过滤器来过滤日志Msg中的特殊字符需要导入其依赖包 janino-2.3.2.jar。其logback.xml


  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <configuration>
  3 
  4     <!-- 控制台输出 -->
  5     <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
  6         <encoder>
  7             <pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
  8         </encoder>
  9     </appender>
 10 
 11     <!-- 时间滚动输出 level为 DEBUG 日志 -->
 12     <appender name="file—debug"
 13         class="ch.qos.logback.core.rolling.RollingFileAppender">
 14         <filter class="ch.qos.logback.classic.filter.LevelFilter">
 15             <level>DEBUG</level>
 16             <onMatch>ACCEPT</onMatch>
 17             <onMismatch>DENY </onMismatch>
 18         </filter>
 19         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
 20             <FileNamePattern>D:/logs/debug.%d{yyyy-MM-dd}.log</FileNamePattern>
 21             <MaxHistory>30</MaxHistory>
 22         </rollingPolicy>
 23         <encoder>
 24             <pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
 25         </encoder>
 26     </appender>
 27 
 28     <!-- 时间滚动输出 level为 ERROR 日志 -->
 29     <appender name="file—error"
 30         class="ch.qos.logback.core.rolling.RollingFileAppender">
 31         <filter class="ch.qos.logback.classic.filter.LevelFilter">
 32             <level>ERROR</level>
 33             <onMatch>ACCEPT</onMatch>
 34             <onMismatch>DENY </onMismatch>
 35         </filter>
 36         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
 37             <FileNamePattern>D:/logs/error.%d{yyyy-MM-dd}.log</FileNamePattern>
 38             <MaxHistory>30</MaxHistory>
 39         </rollingPolicy>
 40         <encoder>
 41             <pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
 42         </encoder>
 43     </appender>
 44 
 45     <!-- 特定过滤含有某字符串的日志 -->
 46     <appender name="file-str"
 47         class="ch.qos.logback.core.rolling.RollingFileAppender">
 48         <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
 49             <evaluator>
 50                 <expression>message.contains("str")</expression>
 51             </evaluator>
 52             <onMatch>ACCEPT</onMatch>
 53             <onMismatch>DENY</onMismatch>
 54         </filter>
 55         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
 56             <FileNamePattern>D:/logs/contains.%d{yyyy-MM-dd}.log
 57             </FileNamePattern>
 58             <MaxHistory>30</MaxHistory>
 59         </rollingPolicy>
 60         <encoder>
 61             <pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
 62         </encoder>
 63     </appender>
 64 
 65     <!-- 数据库输出 -->
 66     <appender name="db" class="ch.qos.logback.classic.db.DBAppender">
 67         <connectionSource
 68             class="ch.qos.logback.core.db.DriverManagerConnectionSource">
 69             <driverClass>com.mysql.jdbc.Driver</driverClass>
 70             <url>jdbc:mysql://host_name:3306/datebase_name</url>
 71             <user>username</user>
 72             <password>password</password>
 73         </connectionSource>
 74     </appender>
 75 
 76     <logger name="java.sql.Connection">
 77         <level value="DEBUG" />
 78     </logger>
 79     <logger name="java.sql.Statement">
 80         <level value="DEBUG" />
 81     </logger>
 82     <logger name="com.ibatis">
 83         <level value="DEBUG" />
 84     </logger>
 85     <logger name="com.ibatis.common.jdbc.SimpleDataSource">
 86         <level value="DEBUG" />
 87     </logger>
 88     <logger name="com.ibatis.common.jdbc.ScriptRunner">
 89         <level value="DEBUG" />
 90     </logger>
 91     <logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate">
 92         <level value="DEBUG" />
 93     </logger>
 94     <logger name="com.danga.MemCached">
 95         <level value="INFO" />
 96     </logger>
 97     <logger name="org.springframework.test">
 98         <level value="DEBUG" />
 99     </logger>
100     <logger name="org.apache.struts2">
101         <level value="DEBUG" />
102     </logger>
103 
104     <root level="DEBUG">
105         <appender-ref ref="stdout" />
106         <appender-ref ref="file—debug" />
107         <appender-ref ref="file—error" />
108         <appender-ref ref="file-str" />
109         <appender-ref ref="db" />
110     </root>
111 
112 </configuration>

### 将 YOLO 格式数据集换为 COCO 格式的实现 YOLOCOCO 是两种常见的目标检测数据集格式,它们之间的主要区别在于标注文件的结构和存储方式。以下是将 YOLO 格式数据集换为 COCO 格式的具体方法。 #### 1. 数据准备 在开始换之前,需要准备好以下内容: - **YOLO 格式的标签文件**:这些是以 `.txt` 文件形式存在的标注文件,位于 `labels/` 文件夹下。 - **图像文件路径列表**:用于构建 COCO 的 `images` 字段。 - **类别名称列表**:定义了数据集中包含的目标类别的名称。 #### 2. 换逻辑 COCO 格式的标注文件是一个 JSON 文件,其基本结构如下: ```json { "info": {}, "licenses": [], "categories": [ {"id": 0, "name": "class_1"}, {"id": 1, "name": "class_2"} ], "images": [ {"id": 0, "file_name": "image_1.jpg", "width": 640, "height": 480}, {"id": 1, "file_name": "image_2.jpg", "width": 640, "height": 480} ], "annotations": [ { "id": 0, "image_id": 0, "category_id": 0, "bbox": [x_min, y_min, width, height], "area": area_of_bbox, "iscrowd": 0 } ] } ``` 为了完成换,需执行以下几个操作: - 构建 `categories` 部分,基于类别名称列表生成对应的 ID 映射关系[^1]。 - 解析每张图片的信息并填充到 `images` 列表中。 - 对于每个标注文件解析边界框坐标,并将其从相对位置 (YOLO 格式) 换为绝对像素位置 (COCO 格式),最后填入 `annotations` 中。 #### 3. Python 实现脚本 下面提供了一个完整的 Python 脚本来完成上述任务: ```python import os import json from PIL import Image def convert_yolo_to_coco(yolo_labels_dir, images_dir, output_json_path, class_names): """ Convert YOLO format dataset to COCO format. :param yolo_labels_dir: Path to the directory containing .txt label files in YOLO format. :param images_dir: Path to the directory containing image files. :param output_json_path: Output path for saving the resulting COCO-format JSON file. :param class_names: List of class names corresponding to indices used in labels. """ # Initialize COCO structure coco_data = { "info": {}, "licenses": [], "categories": [{"id": idx, "name": name} for idx, name in enumerate(class_names)], "images": [], "annotations": [] } annotation_id_counter = 0 # Process each image and its associated label file for img_idx, filename in enumerate(os.listdir(images_dir)): if not filename.lower().endswith(('.png', '.jpg', '.jpeg')): continue img_path = os.path.join(images_dir, filename) img = Image.open(img_path) w, h = img.size # Add image entry coco_image_entry = { "id": img_idx, "file_name": filename, "width": w, "height": h } coco_data["images"].append(coco_image_entry) # Load corresponding label file label_filename = f"{os.path.splitext(filename)[0]}.txt" label_filepath = os.path.join(yolo_labels_dir, label_filename) if not os.path.exists(label_filepath): continue with open(label_filepath, 'r') as lbl_f: lines = lbl_f.readlines() for line in lines: parts = list(map(float, line.strip().split())) cls_id, xc_norm, yc_norm, w_norm, h_norm = map(int, parts[:1]) + parts[1:] # Convert normalized coordinates back to absolute values x_center = xc_norm * w y_center = yc_norm * h box_w = w_norm * w box_h = h_norm * h x_min = int(x_center - box_w / 2) y_min = int(y_center - box_h / 2) # Create annotation entry annotation_entry = { "id": annotation_id_counter, "image_id": img_idx, "category_id": cls_id, "bbox": [x_min, y_min, box_w, box_h], "area": box_w * box_h, "iscrowd": 0 } coco_data["annotations"].append(annotation_entry) annotation_id_counter += 1 # Save result to a JSON file with open(output_json_path, 'w') as out_f: json.dump(coco_data, out_f) if __name__ == "__main__": yolo_labels_directory = "/path/to/yolo/labels/" images_directory = "/path/to/images/" output_json_file = "/path/to/output/coco_format.json" classes_list = ["cat", "dog"] # Replace this with your actual class names. convert_yolo_to_coco( yolo_labels_dir=yolo_labels_directory, images_dir=images_directory, output_json_path=output_json_file, class_names=classes_list ) ``` 此代码实现了从 YOLO 格式COCO 格式换过程[^2]。它通过遍历所有的图片及其关联的标注文件来提取必要的信息,并按照 COCO 的标准格式重组数据。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值