平台配置日志输出和推送到APM与LogStash

场景描述

目前设计器镜像启动后日志文件为out.log,是启动脚本中定向输出了(>>)out.log文件。实际项目可能:

  • 日志输出到特定目录的特定文件名中
  • 指定以日志保留策略(单个文件大小和文件保留个数)
  • 日志输出到APM工具中(如skywalking)
  • 日志推送到LogStash

日志自定义输出

不定向输出,采用自己配置的方式,与标准的SpringBoot工程配置日志一样。两种方式(都是Spring提供的方式):

方式一

bootstrap.yml 里面可以按profiles指定logback的配置文件,具体文件名和文件输入在logback里面进行配置,跟通用的logback配置一致. 例如:

logging:
  config: classpath:logback-pre.xml

方式二

resources的根目录,直接配置 logback-spring.xml, 启动会自动加载。

日志自定义场景

配置日志推送到LogStash

    <!--配置日志推送到LogStash-->
    <contextListener class="pro.shushi.pamirs.demo.core.config.DemoLogbackFiledConfig"/>
    <appender name="LogStash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>127.0.0.1:4560</destination>
        <!-- encoder必须配置,有多种可选 -->
        <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder">
            <!--  SkyWalking插件, log加tid-->
            <provider class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.logstash.TraceIdJsonProvider" />
            <!--在生成的json中会加这些字段-->
            <customFields>
                {"app.name":"pamirs-demo", "app.type":"Microservice", "platform":"pamirs", "env":"dev"}
            </customFields>
            <timeZone>Asia/Shanghai</timeZone>
            <writeVersionAsInteger>true</writeVersionAsInteger>
            <providers>
                <pattern>
                    <pattern>
                        <!--动态的变量-->
                        {
                        "ip": "%{ip}",
                        "server.name": "%{server.name}",
                        "logger_name": "%logger"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>

skywalking的日志rpc上传

    <!-- skywalking的日志rpc上传 -->
    <appender name="SkyWalkingLogs" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
                <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            </layout>
        </encoder>
    </appender>

完整的代码示例

  • Logback自定义字段
package pro.shushi.pamirs.demo.core.config;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.LoggerContextListener;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.spi.ContextAwareBase;
import ch.qos.logback.core.spi.LifeCycle;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 *  Logback自定义字段
 *
 * @author wx@shushi.pro
 * @date 2024/4/17
 */
public class DemoLogbackFiledConfig extends ContextAwareBase implements LoggerContextListener, LifeCycle {

    private boolean started = false;

    @Override
    public boolean isResetResistant() {
        return false;
    }

    @Override
    public void onStart(LoggerContext loggerContext) {
    }

    @Override
    public void onReset(LoggerContext loggerContext) {
    }

    @Override
    public void onStop(LoggerContext loggerContext) {
    }

    @Override
    public void onLevelChange(Logger logger, Level level) {
    }

    @Override
    public void start() {
        if (started) {
            return;
        }
        Context context = getContext();
        // 机器名称
        context.putProperty("server.name", getHostName());
        // 机器IP地址
        context.putProperty("ip", getHostAddress());
        started = true;
    }

    @Override
    public void stop() {
    }

    @Override
    public boolean isStarted() {
        return false;
    }

    private String getHostName() {
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return "";
    }

    private String getHostAddress() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return "";
    }
}
  • logback-dev.xml完整内容
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 日志输出格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="%d |-%p [%tid] %class:%line - %m%n"/>

    <!-- 控制台日志 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <pattern>${CONSOLE_LOG_PATTERN}</pattern><!-- 此处设置输出格式 -->
            </layout>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
    </appender>

    <!-- 文件日志 -->
    <appender name="fileLogger"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>/Users/wangxian/logs/pamirs-demo.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>/Users/wangxian/logs/pamirs-demo-%d-%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- 日志文件的最多存储64MB -->
                <maxFileSize>500MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
           <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <pattern>${CONSOLE_LOG_PATTERN}</pattern><!-- 此处设置输出格式 -->
            </layout>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
    </appender>

    <!--配置日志推送到LogStash-->
    <contextListener class="pro.shushi.pamirs.demo.core.config.DemoLogbackFiledConfig"/>
    <appender name="LogStash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>127.0.0.1:4560</destination>
        <!-- encoder必须配置,有多种可选 -->
        <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder">
            <!--  SkyWalking插件, log加tid-->
            <provider class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.logstash.TraceIdJsonProvider" />
            <!--在生成的json中会加这些字段-->
            <customFields>
                {"app.name":"pamirs-demo", "app.type":"Microservice", "platform":"pamirs", "env":"dev"}
            </customFields>
            <timeZone>Asia/Shanghai</timeZone>
            <writeVersionAsInteger>true</writeVersionAsInteger>
            <providers>
                <pattern>
                    <pattern>
                        <!--动态的变量-->
                        {
                        "ip": "%{ip}",
                        "server.name": "%{server.name}",
                        "logger_name": "%logger"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>

    <!-- skywalking的日志rpc上传 -->
    <appender name="SkyWalkingLogs" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
                <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            </layout>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="LogStash"/>
        <appender-ref ref="SkyWalkingLogs"/>
    </root>

    <!-- Nacos的心跳检测日志级别设置 (会自动继承root 的appender) -->
    <logger name="com.alibaba" level="ERROR">
    </logger>
    <!-- xxl-job心跳检查日志级别 -->
    <logger name="com.xxl.job.core.thread" level="ERROR"/>
</configuration>
  • 分为debug、info、warn、error四种类型的日志信息,分别保存到此四个文件夹中,并按大小和日期进行归档
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->

<!-- 根节点<configuration>,包含下面三个属性:-->
<!-- scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。-->
<!-- scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。-->
<!-- debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。-->
<configuration>
   <contextName>dimples-logback</contextName>
   <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
   <property name="log.path" value="C:/springboot-log/logs" />

   <!-- 彩色日志 -->
   <!-- 彩色日志依赖的渲染类 -->
   <conversionRule conversionWord="clr"
      converterClass="org.springframework.boot.logging.logback.ColorConverter" />
   <conversionRule conversionWord="wex"
      converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
   <conversionRule conversionWord="wEx"
      converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
   <!-- 彩色日志格式 -->
   <property name="CONSOLE_LOG_PATTERN"
      value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />
   <property name="log.colorPattern" value="%magenta(%d{yyyy-MM-dd HH:mm:ss}) %highlight(%-5level) %boldCyan([${springAppName:-},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]) %yellow(%thread) %green(%logger) %msg%n"/>
   <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5level [${springAppName:-},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}] %thread %logger %msg%n"/>
   <!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,%i索引【从数字0开始递增】,,, -->
   <!-- appender是configuration的子节点,是负责写日志的组件。 -->
   <!-- ConsoleAppender:把日志输出到控制台 -->
   <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
      <encoder>
         <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
         <!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
         <charset>UTF-8</charset>
      </encoder>
   </appender>

   <!-- 时间滚动输出 level为 DEBUG 日志 -->
   <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <!-- 正在记录的日志文件的路径及文件名 -->
      <file>${log.path}\debug/log_debug.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}/debug/log-debug-%d{yyyy-MM-dd-HH}.%i.log</fileNamePattern>
         <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
         </timeBasedFileNamingAndTriggeringPolicy>
         <!--日志文件保留天数-->
         <maxHistory>15</maxHistory>
      </rollingPolicy>
      <!-- 此日志文件只记录debug级别的 -->
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
         <level>debug</level>
         <onMatch>ACCEPT</onMatch>
         <onMismatch>DENY</onMismatch>
      </filter>
   </appender>

   <!-- 时间滚动输出 level为 INFO 日志 -->
   <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <!-- 正在记录的日志文件的路径及文件名 -->
      <file>${log.path}\info/log_info.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}/info/log-info-%d{yyyy-MM-dd-HH}.%i.log</fileNamePattern>
         <timeBasedFileNamingAndTriggeringPolicy
            class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
         </timeBasedFileNamingAndTriggeringPolicy>
         <!--日志文件保留天数-->
         <maxHistory>15</maxHistory>
      </rollingPolicy>
      <!-- 此日志文件只记录info级别的 -->
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
         <level>info</level>
         <onMatch>ACCEPT</onMatch>
         <onMismatch>DENY</onMismatch>
      </filter>
   </appender>

   <!-- 时间滚动输出 level为 WARN 日志 -->
   <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <!-- 正在记录的日志文件的路径及文件名 -->
      <file>${log.path}\warn/log_warn.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}/warn/log-warn-%d{yyyy-MM-dd-HH}.%i.log</fileNamePattern>
         <timeBasedFileNamingAndTriggeringPolicy
            class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
         </timeBasedFileNamingAndTriggeringPolicy>
         <!--日志文件保留天数-->
         <maxHistory>30</maxHistory>
      </rollingPolicy>
      <!-- 此日志文件只记录warn级别的 -->
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
         <level>warn</level>
         <onMatch>ACCEPT</onMatch>
         <onMismatch>DENY</onMismatch>
      </filter>
   </appender>
   <!-- RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
   <!--             2.如果日期没有发生变化,但是当前日志的文件大小超过1KB时,对当前日志进行分割 重命名-->
   <!-- 时间滚动输出 level为 ERROR 日志 -->
   <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <!-- 正在记录的日志文件的路径及文件名 -->
      <file>${log.path}\error/log_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/log-error-%d{yyyy-MM-dd-HH}.%i.log</fileNamePattern>
         <timeBasedFileNamingAndTriggeringPolicy
            class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
         </timeBasedFileNamingAndTriggeringPolicy>
         <!--日志文件保留天数-->
         <maxHistory>30</maxHistory>
      </rollingPolicy>
      <!-- 此日志文件只记录ERROR级别的 -->
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
         <level>ERROR</level>
         <onMatch>ACCEPT</onMatch>
         <onMismatch>DENY</onMismatch>
      </filter>
   </appender>
   <!--开发环境:打印控制台-->
   <!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 -->
   <!-- com.dimples.springboot.biz为业务逻辑根包,也就是只要是发生在这个根包下面的所有日志操作行为的权限都是DEBUG -->
   <!-- 级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE  -->
   <springProfile name="dev">
      <logger name="com.dimples.springboot.biz" level="debug" />
   </springProfile>
   <!-- 控制台输出日志级别 -->
   <root level="info">
      <appender-ref ref="CONSOLE" />
      <appender-ref ref="DEBUG_FILE" />
      <appender-ref ref="INFO_FILE" />
      <appender-ref ref="WARN_FILE" />
      <appender-ref ref="ERROR_FILE" />
   </root>

   <!--生产环境:输出到文件-->
   <!--<springProfile name="pro">-->
   <!--<root level="info">-->
   <!--<appender-ref ref="CONSOLE" />-->
   <!--<appender-ref ref="DEBUG_FILE" />-->
   <!--<appender-ref ref="INFO_FILE" />-->
   <!--<appender-ref ref="ERROR_FILE" />-->
   <!--<appender-ref ref="WARN_FILE" />-->
   <!--</root>-->
   <!--</springProfile>-->
</configuration>

Oinone社区 作者:望闲原创文章,如若转载,请注明出处:https://doc.oinone.top/install/7370.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

Like (0)
望闲's avatar望闲数式管理员
Previous 2024年5月18日 pm3:14
Next 2024年5月18日 pm4:45

相关推荐

  • 数据源配置使用注意事项

    启动工程的application.yml内可以通过ds-map为每个模块配置数据源,未在ds-map指定的会根据default-ds-key的值设置默认的数据源, 1. 共一套base库的所有启动工程,相同模块的dsKey名称一定要是一样的 2. 如果有需求2个启动工程中对同一个模块要区分库,如:2个启动工程的“用户user模块”读不同的库,那么需要将配置中“用户user模块”的dsKey配置一致,然后在各自启动工程配置中的数据库链接地址填不一样

    2024年7月25日
    2.1K00
  • 框架之MessageHub(信息提示)

    框架之信息概述 后端除了可以返回错误信息以外,还可以返回调试、告警、成功、信息等级别的信息给前端。但是默认情况下前端只提示错误信息,可以通过前端的统一配置放开提示级别,有点类似后端的日志级别。 框架之MessageHub 在oinone平台中,我们怎么做到友好的错误提示呢?接下来介绍我们的MessageHub,它为自定义错误提示提供无限的可能。 何时使用 错误提示是用户体验中特别重要的组成部分,大部分的错误体现在整页级别,字段级别,按钮级别。友好的错误提示应该是怎么样的呢?我们假设他是这样的 与用户操作精密契合 当字段输入异常时,错误展示在错误框底部 按钮触发服务时异常,错误展示在按钮底部 区分不同的类型 错误 成功 警告 提示 调试 简洁易懂的错误信息 不同信息类型的举例 package pro.shushi.pamirs.demo.core.action; import org.springframework.stereotype.Component; import pro.shushi.pamirs.demo.api.model.PetCatItem; import pro.shushi.pamirs.demo.api.model.PetType; import pro.shushi.pamirs.meta.annotation.Action; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.api.dto.common.Message; import pro.shushi.pamirs.meta.api.session.PamirsSession; import pro.shushi.pamirs.meta.enmu.ActionContextTypeEnum; import pro.shushi.pamirs.meta.enmu.InformationLevelEnum; import pro.shushi.pamirs.meta.enmu.ViewTypeEnum; @Model.model(PetType.MODEL_MODEL) @Component public class PetTypeAction { @Action(displayName = "消息",bindingType = ViewTypeEnum.TABLE,contextType = ActionContextTypeEnum.CONTEXT_FREE) public PetType message(PetType data){ PamirsSession.getMessageHub().info("info1"); PamirsSession.getMessageHub().info("info2"); PamirsSession.getMessageHub().error("error1"); PamirsSession.getMessageHub().error("error2"); PamirsSession.getMessageHub().msg(new Message().msg("success1").setLevel(InformationLevelEnum.SUCCESS)); PamirsSession.getMessageHub().msg(new Message().msg("success2").setLevel(InformationLevelEnum.SUCCESS)); PamirsSession.getMessageHub().msg(new Message().msg("debug1").setLevel(InformationLevelEnum.DEBUG)); PamirsSession.getMessageHub().msg(new Message().msg("debug2").setLevel(InformationLevelEnum.DEBUG)); PamirsSession.getMessageHub().msg(new Message().msg("warn1").setLevel(InformationLevelEnum.WARN)); PamirsSession.getMessageHub().msg(new Message().msg("warn2").setLevel(InformationLevelEnum.WARN)); return data; } } 查询运行返回和效果 1)系统提示的返回结果 2)系统提示示例效果

    2024年5月14日
    1.7K00
  • 函数之触发与定时配置和示例

    异步任务总体介绍 函数的触发和定时在很多场景中会用到,也是一个oinone的基础能力。比如我们的流程产品中在定义流程触发时就会让用户选择模型触发还是时间触发,就是用到了函数的触发与定时能力。 触发任务TriggerTaskAction 触发任务的创建,使用sql-record模块监听mysql的binlog事件,通过rocketmq发送变更数据消息,收到MQ消息后,创建TriggerAutoTask。 触发任务的执行,使用TBSchedule拉取触发任务后,执行相应函数。 项目中引入依赖 1、项目的API工程引入依赖pamirs-core-trigger模块 <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-trigger-api</artifactId> </dependency> 2、DemoModule在模块依赖定义中增加@Module(dependencies={TriggerModule.MODULE_MODULE}) @Component @Module( name = DemoModule.MODULE_NAME, displayName = "oinoneDemo工程", version = "1.0.0", dependencies = {ModuleConstants.MODULE_BASE, CommonModule.MODULE_MODULE, UserModule.MODULE_MODULE, TriggerModule.MODULE_MODULE} ) @Module.module(DemoModule.MODULE_MODULE) @Module.Advanced(selfBuilt = true, application = true) @UxHomepage(PetShopProxy.MODEL_MODEL) public class DemoModule implements PamirsModule { ……其他代码 } 3、项目的boot工程引入依赖 <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-trigger-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-trigger-bridge-tbschedule</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-sql-record-core</artifactId> </dependency> yml文件修改(applcation-xxx.yml) a. 修改pamris.event.enabled和pamris.event.schedule.enabled为trueb. pamirs_boot_modules增加启动模块:trigger、sql_record pamirs: record: sql: #改成自己路径 store: /opt/pamirs/logs … event: enabled: true schedule: enabled: true rocket-mq: namesrv-addr: 127.0.0.1:9876 boot: init: true sync: true modules: – base -…… – trigger – sql_record -…… 新建触发任务 新建PetTalentTrigger类,当PetTalent模型的数据记录被新建时触发系统做一些事情 package pro.shushi.pamirs.demo.core.trigger; import pro.shushi.pamirs.demo.api.model.PetTalent; import pro.shushi.pamirs.meta.annotation.Fun; import pro.shushi.pamirs.meta.annotation.Function; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.trigger.annotation.Trigger; import pro.shushi.pamirs.trigger.enmu.TriggerConditionEnum; @Fun(PetTalent.MODEL_MODEL) @Slf4j public class PetTalentTrigger { @Function @Trigger(displayName = “PetTalent创建时触发”,name = “PetTalent#Trigger#onCreate”,condition = TriggerConditionEnum.ON_CREATE) public PetTalent onCreate(PetTalent data){ log.info(data.getName() + “,被创建”); //可以增加逻辑 return data; } } 定时任务 定时任务是一种非常常见的模式,这里就不介绍概念了,直接进入示例环节 新建PetTalentAutoTask实现ScheduleAction getInterfaceName()需要跟taskAction.setExecuteNamespace定义保持一致,都是函数的命名空间 taskAction.setExecuteFun("execute");跟执行函数名“execute”一致 TaskType需配置为CYCLE_SCHEDULE_NO_TRANSACTION_TASK,把定时任务的schedule线程分开,要不然有一个时间长的任务会导致普通异步或触发任务全部延时。 package pro.shushi.pamirs.demo.core.task; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import pro.shushi.pamirs.core.common.enmu.TimeUnitEnum; import pro.shushi.pamirs.demo.api.model.PetTalent; import pro.shushi.pamirs.meta.annotation.Fun; import pro.shushi.pamirs.meta.annotation.Function; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.domain.fun.FunctionDefinition; import pro.shushi.pamirs.middleware.schedule.api.ScheduleAction; import pro.shushi.pamirs.middleware.schedule.common.Result; import pro.shushi.pamirs.middleware.schedule.domain.ScheduleItem; import pro.shushi.pamirs.middleware.schedule.eunmeration.TaskType; import pro.shushi.pamirs.trigger.enmu.TriggerTimeAnchorEnum; import pro.shushi.pamirs.trigger.model.ScheduleTaskAction; import pro.shushi.pamirs.trigger.service.ScheduleTaskActionService; @Slf4j @Component @Fun(PetTalent.MODEL_MODEL) public class PetTalentAutoTask implements…

    2024年5月25日
    1.6K00
  • Oinone协同开发使用手册

    概述 Oinone平台为开发人员提供了本地环境 – 测试环境之间的协同开发模式,可以使得开发人员在本地环境中设计的模型、函数等元数据实时被测试环境使用并设计。开发人员开发完成对应页面和功能后,可以部署至测试环境直接进行测试。 本篇文章将详细介绍协同开发模式在实际开发中的应用及相关内容。 名词解释 本地环境: 开发人员的本地启动环境 测试环境: 在测试服务器上部署的业务测试环境,业务工程服务和设计器服务共用中间件 业务工程服务:在测试服务器上部署的业务工程 设计器服务: 在测试服务器上部署的设计器镜像 一套环境:以测试环境为例,业务工程服务和设计器服务共同组成一套环境 生产环境: 在生产服务器上部署的业务生产环境 环境准备 部署了一个可用的设计器服务,并能正常访问。(需参照下文启动设计器环境内容进行相应修改) 准备一个用于开发的java工程。 准备一个用于部署测试环境的服务器。 协同参数介绍 用于测试环境的参数 -PmetaProtected=${value} 启用元数据保护,只有配置相同启动参数的服务才允许对元数据进行更新。通常该命令用于设计器服务和业务工程服务,并且两个环境需使用相同的元数据保护标记(value)进行启动。本地环境不使用该命令,以防止本地环境在协同开发时意外修改测试环境元数据,导致元数据混乱。 用法 java -jar boot.jar -PmetaProtected=pamirs 用于本地环境的配置 使用命令配置ownSign(推荐) java -jar boot.jar –pamirs.distribution.session.ownSign=demo 使用yaml配置ownSign pamirs: distribution: session: allMetaRefresh: false # 启用元数据全量刷新(备用配置,如遇元数据错误或混乱,启用该配置可进行恢复,使用一次后关闭即可) ownSign: demo # 协同开发元数据隔离标记,用于区分不同开发人员的本地环境,其他环境不允许使用 启动设计器环境 docker-run启动 -e PROGRAM_ARGS=-PmetaProtected=pamirs docker-compose启动 services: backend: container_name: designer-backend image: harbor.oinone.top/oinone/designer-backend-v5.0 restart: always environment: # 指定spring.profiles.active ARG_ENV: dev # 指定-Plifecycle ARG_LIFECYCLE: INSTALL # jvm参数 JVM_OPTIONS: "" # 程序参数 PROGRAM_ARGS: "-PmetaProtected=pamirs" PS: java [JVM_OPTIONS?] -jar boot.jar [PROGRAM_ARGS?] 开发流程示例图 具体使用步骤详见协同开发支持

    2024年7月24日
    2.4K00
  • 模型字段之序列化方式

    本文核心是带大家全面了解oinone的序列方式,包括支持的序列化类型、注意点、如果新增客户化序列化方式以及字段默认值的反序列化。 字段序列化方式说明 序列化方式 说明 备注 JSON JSON序列化 主要用于模型相关类型字段的序列化,是@Field.serialize默认选项 DOT 点拼接集合元素 COMMA 逗号拼接集合元素 BIT 按位与,2次幂数求和 非@Field.serialize可选项列表,用于二进制枚举序列化不需要配置,由oinone自动推断 字段序列化方式举例 1、给模型PetItemDetail 增加两个字段:petItemDetails类型为List 和 tags类型为List,并设置为不同的序列化方式,petItemDetails为JSON(缺省就是JSON,可不配),tags为COMMA。2、同时设置 @Field.Advanced(columnDefinition = "varchar(1024)"),防止序列化后存储过长。 @Model.model(PetItem.MODEL_MODEL) @Model(displayName = "宠物商品",summary="宠物商品",labelFields = {"itemName"}) public class PetItem extends AbstractDemoCodeModel{ public static final String MODEL_MODEL="demo.PetItem"; @Field(displayName = "品种") @Field.many2one @Field.Relation(relationFields = {"typeId"},referenceFields = {"id"}) private PetType type; @Field(displayName = "品种类型",invisible = true) private Long typeId; @Field(displayName = "详情", serialize = Field.serialize.JSON, store = NullableBoolEnum.TRUE) @Field.Advanced(columnDefinition = "varchar(1024)") private List<PetItemDetail> petItemDetails; @Field(displayName = "商品标签",serialize = Field.serialize.COMMA,store = NullableBoolEnum.TRUE,multi = true) @Field.Advanced(columnDefinition = "varchar(1024)") private List<String> tags; } 字段序列化注意点 必须使用Field#store属性将字段存储设置为NullableBoolEnum.TRUE。 使用Field#serialize属性指定序列化方式,默认为JSON。 如把PetItemDetail设置为存储模型,须在PetItem的petItemDetails字段上使用Field.Relation#store属性将关联关系存储设置为false。不然会同时存储petItemDetails字段和对应的PetItemDetail表记录 注册自己的序列化器 注册自己的序列化器(实现pro.shushi.pamirs.meta.api.core.orm.serialize.Serializer接口), 如oinone的DOT的序列化方式,用type()方法返回值做匹配,serialize和deserialize分别对应序列化和反序列化方法。 package pro.shushi.pamirs.framework.compute.serialize; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.api.core.orm.serialize.Serializer; import pro.shushi.pamirs.meta.common.constants.CharacterConstants; import pro.shushi.pamirs.meta.enmu.SerializeEnum; import pro.shushi.pamirs.meta.util.TypeUtils; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * 点表达式序列生成处理器实现 * @author shushi@shushi.pro * @version 1.0.0 */ @SuppressWarnings("rawtypes") @Slf4j @Component public class DotSerializeProcessor implements Serializer<Object, String> { @Override public String serialize(String ltype, Object value) { if (null == value) { return null; } if (List.class.isAssignableFrom(value.getClass())) { return StringUtils.join((List) value, CharacterConstants.SEPARATOR_DOT); } else { return StringUtils.join(Collections.singletonList(value), CharacterConstants.SEPARATOR_DOT); } } @SuppressWarnings("unchecked") @Override public Object deserialize(String ltype, String ltypeT, String value,…

    2024年5月24日
    2.0K00

Leave a Reply

Please Login to Comment