{"id":30278285,"url":"https://github.com/flyhero/easy-log","last_synced_at":"2025-08-16T12:35:50.951Z","repository":{"id":44469811,"uuid":"464025819","full_name":"flyhero/easy-log","owner":"flyhero","description":"easy-log是基于SpringBoot的一款通用操作日志组件，它指在帮助我们通过注解优雅地聚合项目中的操作日志，对业务代码无侵入。","archived":false,"fork":false,"pushed_at":"2023-12-04T06:03:15.000Z","size":309,"stargazers_count":94,"open_issues_count":0,"forks_count":32,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-08-10T16:46:11.349Z","etag":null,"topics":["biz-log","easy-log","log","log-record","operation-log","operator","spring-aop","spring-boot-starter","springboot"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flyhero.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-02-27T03:19:56.000Z","updated_at":"2025-08-07T12:27:09.000Z","dependencies_parsed_at":"2023-01-26T14:16:21.416Z","dependency_job_id":null,"html_url":"https://github.com/flyhero/easy-log","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/flyhero/easy-log","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyhero%2Feasy-log","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyhero%2Feasy-log/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyhero%2Feasy-log/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyhero%2Feasy-log/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flyhero","download_url":"https://codeload.github.com/flyhero/easy-log/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyhero%2Feasy-log/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270709088,"owners_count":24631992,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-16T02:00:11.002Z","response_time":91,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["biz-log","easy-log","log","log-record","operation-log","operator","spring-aop","spring-boot-starter","springboot"],"created_at":"2025-08-16T12:35:45.431Z","updated_at":"2025-08-16T12:35:50.941Z","avatar_url":"https://github.com/flyhero.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n```text\n                        _             \n                       | |            \n  ___  __ _ ___ _   _  | | ___   __ _ \n / _ \\/ _` / __| | | | | |/ _ \\ / _` |\n|  __/ (_| \\__ \\ |_| | | | (_) | (_| |\n \\___|\\__,_|___/\\__, | |_|\\___/ \\__, |\n                 __/ |           __/ |\n                |___/           |___/ \n\n```\n\n![xxx](https://img.shields.io/badge/version-1.0-green) ![xxx](https://img.shields.io/badge/jdk-1.8-green)  ![xxx](https://img.shields.io/badge/springboot-2.3-green)\n\n- GitHub: [https://github.com/flyhero/easy-log](https://github.com/flyhero/easy-log)\n- Gitee: [https://gitee.com/flyhero/easy-log](https://gitee.com/flyhero/easy-log)\n\n## 1. 项目简介\neasy-log是基于SpringBoot的一款通用操作日志组件，它指在帮助我们通过注解优雅地聚合项目中的操作日志，对业务代码无侵入。\n\n## 2. 使用场景\n所有系统都会有日志，但我们区分了 **系统日志** 和 **操作日志**\n\n- 系统日志：主要用于开发者调试排查系统问题的，不要求固定格式和可读性\n- 操作日志：主要面向用户的，要求简单易懂，反应出用户所做的动作。\n\n通过操作日志可追溯到 某人在某时干了某事情，如：\n\n| 租户  | 操作人 | 时间               | 操作 | 内容                           |\n| ----- | ------ | ------------------ | ---- | ------------------------------ |\n| A租户 | 小明   | 2022/2/27 20:15:00 | 新增 | 新增了一个用户：Mr.Wang        |\n| B租户 | 大米   | 2022/2/28 10:35:00 | 更新 | 修改订单 [xxxxxx] 价格为 xx 元 |\n| C租户 | 老王   | 2022/2/28 22:55:00 | 查询 | 查询了名为: [xx] 的所有交易    |\n\n\n## 3. 功能特性\n - 快速接入：基于SpringBoot，轻量级，引入starter即可食用\n - SpEL解析：直接写表达式解析入参\n - 自定义函数：支持目标方法执行前/后的自定义函数\n\n## 4. 设计图\n\n![](./docs/images/aop-design.png)\n\n## 5. 使用方法\n### 5.1 引入依赖\n\n已上传到中央仓库：https://search.maven.org/search?q=g:io.github.flyhero\n\n在pom.xml中引入：\n```\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.flyhero\u003c/groupId\u003e\n    \u003cartifactId\u003eeasylog-spring-boot-starter\u003c/artifactId\u003e\n    \u003cversion\u003e2.1.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n### 5.2 配置\n\n```properties\n# 默认开启可不填，禁用是填 false\neasylog.enable=true\n# 当有多个服务用时，用于区分不同服务下的操作日志，默认取 spring.application.name\neasylog.platform=easylog-example\n# 是否在控制台打印 banner,默认打印\neasylog.banner=false\n```\n\n### 5.3 使用注解\n在要记录操作日志的方法上添加EasyLog注解并填写对应内容：\n\n```java\n@EasyLog(module = \"用户模块\", operator = \"{{#userDto.toString()}}\", type = \"新增\",\n        success = \"测试 {functionName{#userDto.name}}\",\n        condition = \"{{#userDto.name == 'easylog'}}\")\npublic String test(UserDto userDto) {\n    return \"test\";\n}\n```\n| 字段        | 意义                            | 支持SpEl表达式 | 必填 |\n| ----------- | ------------------------------- | ---------- | ---- |\n| tenant      | 租户，SAAS系统中区分不同租户    | 是         | 否   |\n| operator    | 操作者                          | 是         | 否   |\n| module      | 模块，区分不同业务模块          | 否         | 否   |\n| type | 操作类型，形如：增删改查        | 否         | 否   |\n| bizNo       | 业务编号，便于查询   | 是         | 否   |\n| success     | 成功日志模板内容                  | 是         | 是   |\n| fail        | 操作失败时的模板内容            | 是         | 否   |\n| detail      | 额外的记录信息                  | 是         | 否   |\n| condition   | 是否记录的条件 (默认:true 记录) | 是         | 否   |\n\n\u003e 注意: \n\u003e \n\u003e 1.当使用自定义函数时，必须使用双花括号包起来（如：{getNameById{#id}} ），便于解析。\n\u003e \n\u003e 2.当不使用自定义函数时，可以直接使用SpEl表达式（如：#name）\n\u003e 如果获取方法的执行结果或错误信息，可使用{{#_result}}或#_result 和 {{#_errMsg}}或#_errMsg。\n\n### 5.4 获取操作者\n如果不在上述注解中指定租户和操作人，那么可统一设置，方式如下：\n实现 **IOperatorService** 接口，并交给Spring管理。\n```java\n@Service\npublic class OperatorGetService implements IOperatorService {\n    @Override\n    public String getOperator() {\n        //可从请求头中获取token解析用户\n        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();\n        String token = request.getHeader(\"token\");\n        return \"admin\";\n    }\n    @Override\n    public String getTenant() {\n        return \"company\";\n    }\n}\n```\n\n### 5.5 自定义函数\n当方法参数中，没有你想要的数据时，我们可以通过自定义函数来实现。\n实现 **ICustomFunction** 接口，并交给Spring管理。\n```java\n@Component\npublic class GetRealNameById implements ICustomFunction {\n    @Override\n    public boolean executeBefore() {\n        return false;\n    }\n    @Override\n    public String functionName() {\n        return \"GetRealNameById\";\n    }\n    @Override\n    public String apply(String value) {\n        return \"easylog\".equals(value) ? \"good\" : value;\n    }\n}\n```\n\n### 5.6 接收操作日志\n我们接收到操作日志后，可根据实际情况来选择如何处理，是存储到数据库还是发送到MQ都可以。\n实现 **ILogRecordService** 接口，并交给Spring管理。\n```java\n@Slf4j\n@Service\npublic class OpLogRecordService implements ILogRecordService {\n    @Override\n    public void record(EasyLogInfo easyLogInfo) {\n        log.info(\"hello easy-log:{}\", JsonUtils.toJSONString(easyLogInfo));\n    }\n}\n```\n\n## QA\n### 1、同一类中互相调用含 @Easylog 注解的方法，只有一条日志\n这是因为 Spring AOP 无法拦截内部方法调用。解决方案：\n\n1、修改，不要出现“自调用”的情况，这是Spring文档中推荐的“最佳”方案；\n\n2、若一定要自调用，那么在 SpringBoot 启动类中加一个注解：\n```java\n@EnableAspectJAutoProxy(exposeProxy = true)\n```\n然后将自调用的方法, this.test2() 替换为：((当前类) AopContext.currentProxy()).test2();\n\n### 2、EasyLog 注解中 许多方法返回的是 String，如何存储更多的信息？\n\n可将String当作json字符串，比如 操作者 operator 是String类型，那么它可以存储以下字符串信息：\n```text\n{\"id\": 1, \"name\": \"admin\", \"ip\": \"127.0.0.1\"}\n```\n\n## Change Log\n\n| 版本    | 内容                                       |状态 |\n|-------|------------------------------------------|----|\n| 2.1.3 | 1.修复success 或 fail 中不包含 SpEL 表达式，报异常问题   | 推荐使用|\n| 2.1.1 | 1.修复前置函数的返回值获取错误                         | 推荐使用|\n| 2.1.0 | 1.支持同一方法多个EasyLog注解  2.自定义函数参数支持Object类型 | 推荐使用|\n| 2.0.0 | 增加配置，提升性能，不兼容低版本                         | 推荐使用|\n| 1.0.1 | 基本型，性能欠佳                                 | 不推荐|\n| 1.0.0 | 基本型，有bug，性能欠佳                            | 不要使用|\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflyhero%2Feasy-log","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflyhero%2Feasy-log","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflyhero%2Feasy-log/lists"}