精华内容
下载资源
问答
  • 关于这个级别的日志,上次讲了2个方案: 1、aop切面,使用环绕事件,在proceed()前后分别处理,组织操作前后的参数 2、提供公用的工具类方法,开启线程处理 今天主要是再补充下方案1,方案一其实可以增加一个...

        关于这个级别的日志,上次讲了2个方案:

        1、aop切面,使用环绕事件,在proceed()前后分别处理,组织操作前后的参数

        2、提供公用的工具类方法,开启线程处理

        今天主要是再补充下方案1,方案一其实可以增加一个声明注解,接口方法上注解,描述方法的具体作用。看硬货:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface OperateLogAnno {
        /**
         * 日志描述
         *
         * @return
         */
        String logDesc();
    }

    增加一个上面这样的声明类。然后方法名上注解:

    @OperateLogAnno(logDesc = "操作描述说明")

    剩下就是aop切面类了:

    @Around("addPointcut() || updatePointcut()")
    public Object Around(ProceedingJoinPoint pjp) throws Throwable {
        Signature sig = pjp.getSignature();
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        MethodSignature msig = (MethodSignature) sig;
        Object target = pjp.getTarget();
        Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
        // 类名
        String targetName = target.getClass().getSimpleName();
        // 方法名
        String methodName = currentMethod.getName();
        Object[] args = pjp.getArgs();
        // 方法的第1个参数
        Object model = args[0];
        Class modelClass = model.getClass();
        // 查询ID
        Integer id = null;
        // 需要通过反射获取的Mapper类
        Mapper<Object> mapper = null;
        // 更新前数据行
        String beforeJson = "{}";
        // 更新后数据行
        String afterJson;
    
        // 是否要记录数据行日志
        boolean need = false;
        // 是否是新增操作,默认为新增
        boolean isAdd = true;
        OperateLogAnno anno = currentMethod.getAnnotation(OperateLogAnno.class);
        if (anno != null) {
            need = true;
        }
        if (need) {
            // 获取查询ID
            Method getId = modelClass.getMethod("getId");
            id = Integer.class.cast(getId.invoke(model));
            if (id != null && id > 0) {
                isAdd = false; // 修改操作
            }
            targetName = targetName.substring(0, targetName.indexOf("ServiceImpl"));
            String mapperName = (new StringBuilder()).append(Character.toLowerCase(targetName.charAt(0)))
                    .append(targetName.substring(1)).toString() + "Mapper";
            mapper = BeanHeader.getBean(mapperName);
        }
    
        if (need) {
            Object before;
            // 修改操作,先取出未修改的数据行
            if (!isAdd) {
                before = mapper.selectByPrimaryKey(id);
            } else {
                before = "{}";
            }
            beforeJson = JSON.toJSONString(before);
        }
    
        // 执行原始方法
        Object object = pjp.proceed();
    
        Result<?> result = (Result<?>) object;
        // 返回值异常,直接返回结果
        if (result.getCode() != ResultCode.SUCCESS.code()) {
            return result;
        }
    
        if (need) {
            // 新增操作,从返回结果中获取数据行id
            if (isAdd) {
                Result<Integer> addResult = (Result<Integer>) object;
                id = addResult.getData();
            }
            if (id != null && id > 0) {
                Object after = mapper.selectByPrimaryKey(id);
                afterJson = JSON.toJSONString(after);
    
                Class clazz = after.getClass();
                // 机构ID
                Integer orgId = 0;
                try {
                    Method getOrgId = clazz.getMethod("getOrgId");
                    orgId = Integer.class.cast(getOrgId.invoke(after));
                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                    log.info("对象{}没有方法getOrgId,设置默认值", clazz.getSimpleName());
                }
                // 项目ID
                Integer subjectId = 0;
                try {
                    Method getSubjectId = clazz.getMethod("getSubjectId");
                    subjectId = Integer.class.cast(getSubjectId.invoke(after));
                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                    log.info("对象{}没有方法getSubjectId,设置默认值", clazz.getSimpleName());
                }
                // 创建者ID
                Integer createBy = BusinessConstant.CREATE_BY_DEFAULT;
                try {
                    Method getCreateBy = modelClass.getMethod("getCreateBy");
                    createBy = Integer.class.cast(getCreateBy.invoke(model));
                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                    log.info("对象{}没有方法getCreateBy设置默认值", clazz.getSimpleName());
                }
                // 更新者ID
                Integer updateBy = BusinessConstant.CREATE_BY_DEFAULT;
                try {
                    Method getUpdateBy = modelClass.getMethod("getUpdateBy");
                    updateBy = Integer.class.cast(getUpdateBy.invoke(model));
                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                    log.info("对象{}没有方法getUpdateBy设置默认值", clazz.getSimpleName());
                }
                //记录数据业务级日志
                OperateLogUtil.sendOperateLog(afterJson, beforeJson, orgId, subjectId, targetName, anno.logDesc(),
                        methodName, isAdd ? createBy : updateBy);
            }
        }
    
        return result;
    }

    上面这个方法是以Object object = pjp.proceed();这行为界,前面组织操作前的json字符串,后面组织操作后的json字符串。当然都是通过反射获取对应的mapper,从参数里取id,然后查询,组织参数。保存依然是调用的开启线程保存日志的公共方法。

    到这里就没有什么其他可说的了,关键点都跟大家分享了。下面总结下这个方案的优劣吧。

    1、在proceed()前后写的代码,没有开启线程,肯定对接口响应有影响

    2、只能单表操作

    第1点可以使用多线程,前后分别开线程,ThreadLocal 配合CountDownLatch在调用保存日志方法,减少对接口响应的影响。

    第2点那几乎就是无解了。除非将一个方法里的多表操作拆分成多个方法,一个方法里只操作一张表,如果操作多表就一个方法里调用多个方法,不知道这样是否可行,没有实际试验。

     

    展开全文
  • Storm处理实时日志

    千次阅读 2017-04-25 18:18:46
    之前写过一篇MapReduce清洗数据,比起MR,在工作中更早使用了Storm进行实时的日志清理 Storm的输入和输出相当灵活,我处理的主要输入流都是Kafka,输出流有Kafka和Scribe

    用Storm处理实时日志

    • 之前写过一篇用MapReduce清洗数据,比起MR,在工作中更早使用了Storm进行实时的日志清理
    • Storm的输入和输出相当灵活,我处理的主要输入流都是Kafka,输出流有Kafka和Scribe

    主类配置Topology

    Storm的Topology,代表整个处理流程的逻辑拓扑,在构建TopologyBuilder实例时,可以设置Spout和Bolt

    TopologyBuilder builder = new TopologyBuilder();
    
    builder.setSpout("KAFKA_SPOUT", new KafkaSpout(), kafkaSpoutNum);
    builder.setBolt("PARSER_BOLT", new ParserBolt(), parserBoltNum).shuffleGrouping("KAFKA_SPOUT");
    
    • setSpout和setBolt的时候需要指定该Spout和Bolt的ID
    • setSpout和setBolt的时候可以指定Spout和Bolt的数量
    • setBolt的时候需要说明该Bolt如何消费流入它的数据,本例中流入的数据来自KafkaSpout,通过shuffleGrouping的方式消费

    配置完成后提交该topology:

    Config conf = new Config();
    
    /* Submit topology */
    StormSubmitter.submitTopology(group, conf, builder.createTopology());

    Topology就像一个任务框架,业务人员按着这个框架来编程就可以了
    Spout负责从数据源处读取数据,吐到拓扑里,因为从Kafka消费数据是很常见的应用,所以直接复用KafkaSpout就好,不用自己另外实现
    解析和清洗日志的具体逻辑在Bolt中实现,这里实现了一个ParserBolt

    Bolt负责具体计算

    • Storm中流淌的数据单元是Tuple,可以由用户自定义
    • Bolt可以有多级,最后一级Bolt会定期把结果写到目标存储
    • 自己实现的Bolt继承自BaseBasicBolt,具体处理逻辑在函数execute()中实现
    public class ParserBolt extends BaseBasicBolt {
    
        public void prepare(Map stormConf, TopologyContext context) {
    
        }
    
        public void execute(Tuple tuple, BasicOutputCollector collector) {
    
            String input = String.valueOf(tuple.getValue(0));
            String[] lines = input.split("\n");
    
            for (int i = 0; i < lines.length; i++) {
                // process
                // writeTo
            }
        }
    
        public Map<String, Object> getComponentConfiguration() {
            Map<String, Object> conf = super.getComponentConfiguration();
            if (conf == null) {
                conf = new Config();
            }
            conf.put(Config.TOPOLOGY_TICK_TUPLE_FREQ_SECS, 60);    //设置tick的时间为60秒,实现一些定时操作。
            return conf;
        }
    }    
    
    展开全文
  • 企业开发中的异常处理日志

    千次阅读 2016-03-02 11:45:58
     1.1)异常处理 Presentation: 表示层需要捕捉异常以便对用户进行适当的提示。例如转账操作中的余额不足等;Business:面向过程的开发业务逻辑可以理解为经典的数据结构+算法。面向对象的业务逻辑可以理解为一个...

    1)首先从Presentation, Business, DAO层的角度来看

         1.1)异常处理

    • Presentation: 表示层需要捕捉异常以便对用户进行适当的提示。例如转账操作中的余额不足等;
    • Business:面向过程的开发业务逻辑可以理解为经典的数据结构+算法。面向对象的业务逻辑可以理解为一个复杂模型中的一个动作,在产生异常时需要尽可能的保持原始信息以便分析。
    • DAO:记录数据库操作以便查找原因。

         1.2)日志

    • Presentation:表示层目前一般不写日志;
    • Business:此日志记录可以从不同的维度来分析,包括业务Type, time, user等等;
    • DAO:主要是异常处理的日志;

    2)异常处理与日志都应采用AOP来实现;

    3)Transaction(事务)也应采用AOP实现;
    展开全文
  • 相信只有真正做过每秒近百万以上的实时日志处理业务,遇到过棘手问题,才能深刻感受我们当时越不过高坎的窘境与解决问题后的狂喜。 本文首发于我们的团队博客,文章内容详见:每秒百万流式日志处理架构的开发运维...

    荣幸之至,我们团队在实时日志分析、搜索项目中曾经应对过百万级的挑战,在这方面有长足的进步。本文以笔记和问答的形式记录了我们曾经遇到过的实际问题及解决方案,而非小白式的大数据科普文章。相信只有真正做过每秒近百万以上的实时日志处理业务,遇到过棘手问题,才能深刻感受我们当时越不过高坎的窘境与解决问题后的狂喜。

    本文首发于我们的团队博客,文章内容详见:每秒百万级流式日志处理架构的开发运维调优笔记

    展开全文
  • 本发明实施例提供的一种系统日志处理方法包括:访问生成系统日志的设备,从该设备采集系统日志;将采集到的系统日志的格式与指定的设备模板进行匹配,确认各系统日志对应的设备类型;根据各系统日志的设备类型,...
  • java异常处理日志规范 异常规约 service层的异常可以try{}catch(){},但是try后必须要显示的throw出去,这样才能被...最后一的异常一定要Exception来接,保证所有的异常都可以被接住处理掉(抛出或是记录...
  • 日志处理

    千次阅读 2008-03-29 20:56:00
    Log是什么?Log最早来源于航海日志,是用来记录航海过程中的所见所闻。 在应用程序开发领域,特别是企业应用程序,需要在程序不停止的情况下,能够分析程序的运行过程。这个时候就需要把程序运行过程中的数据内容...
  • 手把手教你ELK处理异常日志告警

    千次阅读 2020-08-11 18:08:23
    而因为没有实时处理修复,客户的业务很可能被中断,将会造成巨大的经济和名声损失。 对于开发人员而言,程序每次出现问题,都要查看机器上的日志定位问题,看是代码逻辑问题,还是调用API失败。因为请求接收是随机
  • 容器日志处理及实现

    千次阅读 2017-04-28 11:05:11
    容器日志输出形式:目前容器日志有两种输出形式: stdout,stderr 标准输出 这种形式的日志输出我们可以直接使用docker ...收集方式:不论你的业务容器日志如何输出,都是可以使用统一的日志收集器收集。常见的日志收集
  • 日志平台为集团所有业务系统提供日志采集、消费、分析、存储、索引和查询的一站式日志服务。主要为了解决日志分散不方便查看、日志搜索操作复杂且效率低、业务异常无法及时发现等等问题。 随着有赞业务的发展与增长...
  • Spark项目实战:大数据实时流处理日志(非常详细)

    万次阅读 多人点赞 2019-04-02 18:51:07
    实战概览一、实战内容二、大数据实时流处理分析系统简介1.需求2.背景及架构三、实战所用到的架构和涉及的知识1.后端架构2.前端框架四、项目实战1.后端开发实战1.构建项目2.引入依赖3.创建工程包结构4.编写代码5.编写...
  • 随着数据已经逐步成为一个公司宝贵的财富,大数据团队在公司往往会承担更加重要的角色。...在这里根据七牛云在日增千亿日志分析工作,和大家分享一下大数据技术架构选型的一些经验。   大数据架构师在关...
  • 业务系统日志记录规范总结

    千次阅读 2019-08-28 16:01:09
    业务系统日志记录规范 注意 应用中应该充满了日志记录信息,日志甚至比逻辑代码还要多; 集成 seluth ,开启消息链路;不开启日志上传,不集成 zipkin; 应该避免日志记录过程中出现异常,比如 log.debug(requst...
  • 从ELK到EFK,日志系统的高级玩法儿

    万次阅读 2017-10-19 13:58:41
    为了提供分布式的实时日志搜集和分析的监控系统,我们采用了业界通用的日志数据管理解决方案,主要包括Elasticsearch、Logstash和Kibana三个系统。
  • ELK/ELFK(7.3 ) 企业PB级日志系统实战

    千人学习 2019-12-25 11:42:57
    包含的组件有Filebeat,Logstash,Elastic,Kibana等 本堂课引入Kafka 让Elastic Stack 能适应企业PB业务日志量 并弥补传统ELk架构的不足   ★ 学完这门课程会获得什么?   首先从零开始教你部署Elastic...
  • 程序日志(AppLog)有什么特点? 内容最全:程序日志是由程序员给出,在重要的地点、变量数值以及异常都会有记录,可以说线上90%以上Bug都是依靠程序日志输出定位到 格式比较随意:代码往往经过不同人开发,每...
  • Python之日志处理(logging模块)

    千次阅读 2017-05-25 08:13:00
    Python之日志处理(logging模块) 本节内容 日志相关概念 logging模块简介 使用logging提供的模块级别的函数记录日志 logging模块日志处理流程 使用logging四大组件记录日志 配置logging的几种...
  • 企业微信万亿级日志检索系统

    千次阅读 2021-05-20 00:11:33
    作者:datonli,腾讯 WXG 后台开发工程师背景开发在定位问题时需要查找日志,但企业微信业务模块日志存储在本机磁盘,这会造成以下问题:日志查找效率低下:一次用户请求涉及近十个模块,几...
  • python深入之日志处理(logging)

    千次阅读 2018-08-15 20:17:18
    logging模块日志处理流程 使用logging四大组件记录日志 配置logging的几种方式 向日志输出中添加上下文信息 参考文档 一、日志相关概念 日志是一种可以追踪某些软件运行时所发生事件的方法。软件开发人员...
  • 以下是2012年一个公司内部项目的技术总结,涉及到的方面比较多比较杂,拿出来和大家分享下。如果有更好的方案或者想法请联系我,谢谢...主要应用场景是收集大量的运行时日志,分析并结构化存储,提供数据查询和展现。
  • django日志logging的配置以及处理

    千次阅读 2019-03-24 16:04:20
    一、日志相关概念 日志是一种可以追踪某些软件运行时所发生事件的方法。软件开发人员可以向他们的代码中调用日志记录相关的方法来表明发生了某些事情。一个事件可以一个可包含可选变量数据的消息来描述。此外,...
  • ELK大规模日志实时处理系统

    千次阅读 2019-03-26 18:35:27
    ELK可以将我们的系统日志、网站日志、应用系统日志等各种日志进行收集、过滤、清洗,然后进行集中存放并可用于实时检索、分析。 这三款软件都是开源软件,通常是配合使用,而且又先后归于Elastic.c...
  • SSH异常和日志处理方案

    千次阅读 2014-03-13 13:46:13
    SSH异常和日志处理方案 1. 异常的种类  Java异常机制是为了对程序中可能出现的已知错误进行捕获,并进行相应处理。从是否反馈给用户来看,存在三类异常: 数据库操作异常: 系统异常:这类异常(如 应用...
  • logback高级特性,异步记录日志

    千次阅读 2017-08-03 09:29:00
    异步记录日志 AsyncAppender,异步记录日志。 工作原理: 当Logging Event进入AsyncAppender后,AsyncAppender会调用appender方法,append方法中在将event填入Buffer(这里选用的数据结构为...
  • 百亿级日志系统架构设计及优化

    千次阅读 2018-06-18 09:00:00
    日志数据是最常见的一种海量数据,以拥有大量用户群体的电商平台为例,双 11 大促活动期间,它们可能每小时的日志数量达到百亿规模,海量的日志数据暴增,随之给技术团队带来严峻...
  • DB2活动日志满情况分析与处理

    千次阅读 2019-01-05 15:06:15
    [test@demo ~]$ db2 ? sql0964 SQL0964C The transaction log for the database is full. Explanation: ...活动日志一般有下面2种情形: 1.事务特别大,迅速占满日志空间(比如insert非常多数据)  L...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 145,942
精华内容 58,376
关键字:

一般业务处理日志用什么级