精华内容
下载资源
问答
  • Psychopy | 第4期:实验数据的收集与处理1 相关概念的简单引入2 被试信息录入3 反应时记录4 正确率记录5 完整代码展示6 系列课程的总结 Hello, 这里是行上行下,我是喵君姐姐~ 最近在家实在无聊,所以只好安安心...

    img
    img
    Hello,
    这里是行上行下,我是喵君姐姐~

    最近在家实在无聊,所以只好安安心心学习啦。你最近在家干什么呢?

    今天,继续邀请阿槑给你带来Psychopy系列教程,带来实验数据的收集与处理,希望你会继续喜欢并且一直支持哟~

    1 相关概念的简单引入

    在前几期,我们已经学习了Psychopy入门数据类型与运算符条件与循环flanker范式的完整编程

    但是,在心理学实验中,除了要在屏幕上呈现想要的刺激,我们还希望计算机能够帮助我们收集被试基本信息、反应时以及正确率等指标。

    那么如何达到这一目的呢?

    2 被试信息录入

    对于被试信息,我们将使用 psychopy 中的 gui 来进行收集,所谓 gui ,就是一个被试可以在其中填写信息的对话框,如图:
    img
    在导入 gui 后,我们使用 gui 中的 DlgFromDict 来进行功能的实现:

    from psychopy import core, gui #导入  
    info = {'observer':'01_xxx','gender':['m','f'],'age':18}  
    dlg = gui.DlgFromDict(info, title='flanker', order=['observer','gender','age']) #设置gui  
    if dlg.OK: #单击 OK 后的操作      
    	pass #占位符  
    else:      
    	core.quit()  
    

    可以看到,我们先定义了一个字典来储存需要填写信息的标题以及对应的默认内容,之后我们使用 DlgFromDict 将字典导入 gui 并设置 gui 的标题(title)以及内容顺序(order)。

    最后用一个 if 函数来控制 OK 按键使其继续后面的操作,或者 Cancel 按键退出整个程序。因为这里的退出需要使用 core,因此同样需要在开头进行导入。

    下一步,我们需要确定一下我们最终记录的数据文档的输出路径及文件名。

    首先,我们在程序所在路径,也就是我们程序脚本所在的位置建立一个 data 文件夹用于存放数据。

    之后,我们先以字符串的形式定义文件名,为了防止文件重复,将会通过 time 获取当前系统时间并添加到文件名中。

    import time  
    date = time.strftime("_20%y_%m_%d_%H%M", time.localtime()) #获取当前时间  
    file = 'data/'+info['observer']+'_'+info['gender']+'_'+str(info['age'])+date #文档名(含路径)  
    

    这里的 ‘%y’ , ‘%m’, ‘%d’, ‘%H%M’ 被称为占位符。所谓占位符,可以理解为先占据一个位置,以便之后添加需要填进去的内容。当需要填入的内容过长或需要进行实时获取时,我们常用占位符来暂时补齐位置。

    不同性质的内容需要不同的占位符,常见的占位符包括 ‘%s’ 字符串,’%d’ 整数,’%f’ 浮点数。

    当我们获得了文件名以后,使用 with open…as… 进行相应的文档操作。

    with open("%s.csv"%(file),'a') as D: #写入表头      
    	D.write('flanker'+','+'center'+','+'RT'+','+'accuracy'+'\n') 
    

    简要分析如下:
    img
    一般来讲,实验过程中所输出的数据均写入 csv 文档中,csv 文档可以使用 excel 打开并比我们平时用的 xls 要更加简单。在 csv 文档中,不同单元格之间仅仅以逗号作为分隔符来进行分隔。

    该段代码的输出效果如下:
    img
    除了所介绍的这种简便的方法,对于文件夹、文档的操作还可以使用 python 中的 os 来进行操作,但是 os 对于含有中文的路径不是特别友好,因此这里将不再介绍。

    当我们准备好文档后,就可以使用 with open…as… 不断地对文档内容进行写入,只需要与表头相对应即可。

    对于我们的例子 flanker 范式来说,我们所要收集的是被试的每次反应的反应时以及正确与否。

    3 反应时记录

    在 psychopy 的 Window 中,flip() 方法正好含有该方法运行时距离整个程序开始时的时间,因此我们只需要找到反应屏的 flip() 时间与前一个屏的 flip() 时间做差,就可以得到被试的反应时间。

    from psychopy import event  
    for frame in range(fix_times): #注视点呈现      
    	fix.draw()      
    	time0 = Win.flip()      
    	print(time0)            
    
    while True:      
    	[s.draw() for s in stims] #刺激呈现      
    	time1 = Win.flip()      
    	if len(event.getKeys(['left','right'])) > 0: break    
    
    RT = time1 - time0 #计算反应时  
    

    4 正确率记录

    我们要获得正确率,记录每一次被试的反应时否正确即可,我们默认正确记为1,错误或未反应记为0。

    from psychopy import event  
    b=0 #设置变量 b 的起始值用于后面控制呈现中止  
    while True: #呈现刺激      
    	[s.draw() for s in stims]      
    	time1 = Win.flip()                
    
    	for key in event.getKeys(): #收集按键          
    		if key in ['left', 'right']:              
    			RT = round((time1-time0)*1000) #计算反应时              
    			b=1              
    			break #跳出收集按键的 for 循环      
    	if b==1:          
    		b=0 #b设置回默认          
    		break #跳出呈现的 while 循环        
    
    if (stims[2].flipHoriz==True and key=='right') or\
       (stims[2].flipHoriz==False and key=='left'): #判断按键是否正确      
       acc=1  
    else:      
       acc=0  
    

    我们把单纯的监测按键加上了判断,这里的判断方法为判断中间的箭头 stims[2] 是否进行了翻转,如果发生了翻转那么呈现出来的是 →,则被试反应为 ‘right’ 时为正确反应,反之亦然。

    同时设置变量 b 以控制跳出呈现屏。

    到此,我们获得了每个试次的被试反应时以及其判断正确与否的情况,我们下面只需要将其输出到文档即可,同样可用with open。

    with open("%s.csv"%(file),'a') as D:      
    	D.write(trial[0]+','+trial[1]+','+str(RT)+','+str(acc)+'\n')  
    

    如此,我们完整的 flanker 范式也就完成了,其输出效果如下:
    img

    5 完整代码展示

    最后我们附上完整代码:

    # -*- coding: utf-8 -*-
    """  
    The demo of flanker    
    @author: A Mei  
    """        
    from psychopy import visual, event, gui, core    
    import time, random    #导入
    
    #设置gui
    info = {'observer':'01_xxx','gender':['m','f'],'age':18}    
    dlg = gui.DlgFromDict(info, title='flanker', order=['observer','gender','age'])  
    if dlg.OK:        
    	pass    
    else:        
    	core.quit()    
    
    #设置数据文档
    date = time.strftime("_20%y_%m_%d_%H%M", time.localtime())  #设置文件
    file = 'data/'+info['observer']+'_'+info['gender']+'_'+str(info['age'])+date
    with open("%s.csv"%(file),'a') as D:        
    	D.write('flanker'+','+'center'+','+'RT'+','+'accuracy'+'\n') 
    
    #设置窗口、注视点、结束语        
    Win = visual.Window((1024,768), color=(128,128,128), fullscr=False, units='pix',colorSpace='rgb255')      
    fix = visual.TextStim(Win, text='+', color='black', height=50,bold=True)    
    endPrompt = visual.TextStim(Win, text='实验结束,谢谢!', color='black', height=60)    
    
    #设置各部分呈现时间    
    Rate = 60    
    Dura = 1000/Rate    
    fix_Dura = 300    
    blank_Dura = 500    
    fix_times = int(round(fix_Dura/Dura))    
    blank_times = int(round(blank_Dura/Dura))    
    
    #设置自变量 
    var = []    
    for flanker in ['left', 'right']:     
    	for center in ['same','diff']:            
    		var.append([flanker, center])    
    random.shuffle(var)    
    
    #设置刺激位置
    sites = []    
    for site in range(5):        
    	sites.append((-100+50*site,0))    
    
    #开始循环   
    a = 0    
    b = 0    
    for trial in var:        
    	a+=1        
    	#设置是否翻转    
    	stims = []        
    	for stim in range(5):                        
    		if (trial[0] == 'left' and trial[1] == 'diff' and stim == 2) or\
    		(trial[0] == 'right' and trial[1] == 'diff' and stim != 2) or\
    		(trial[0] == 'right' and trial[1] == 'same'):                
    			Horiz = True            
    		else:                
    			Horiz = False            
    		#定义箭头                
    		arr = visual.TextStim(Win, text='←', color='black', height=50, pos=(-200+100*stim,0),flipHoriz=Horiz, bold=True)            
    		stims.append(arr)        
    	#呈现注视点    
    	for frame in range(fix_times):            
    		fix.draw()            
    		time0 = Win.flip()        
    	#呈现刺激并收集反应时            
    	while True:            
    		[s.draw() for s in stims]            
    		time1 = Win.flip() 
    		                       
    		for key in event.getKeys():                
    			if key in ['left', 'right']:                    
    				RT = round((time1-time0)*1000)                    
    				b=1                    
    				break            
    		if b==1:                
    			b=0                
    			break        
    	#判断被试反应是否正确        
    	if (stims[2].flipHoriz==True and key=='right') or\
    		(stims[2].flipHoriz==False and key=='left'):                
    		acc=1        
    	else:            
    		acc=0        
    	#呈现空屏            
    	for frame in range(blank_times):            
    		Win.flip()        
    	#写入数据        
    	with open("%s.csv"%(file),'a') as D:         
    		D.write(trial[0]+','+trial[1]+','+str(RT)+','+str(acc)+'\n')        
    	#呈现结束语        
    	if a==len(var):            
    		while True:                
    			endPrompt.draw()                
    			Win.flip()                
    			if len(event.getKeys()) > 0: break            
    		Win.close()    
    

    到现在,我们的 psychopy 系列就要告一段落了。虽然相较于 builder(类似e-prime),coder 更为繁琐,难度也略大。但是其精确性与自由性是 builder 无法比拟的。

    当然,本系列只是以实现想要的功能为目的,因此并没有介绍特别多的方法。同时,如果想要比较熟练地进行 psychopy 程序的编写,大量的练习是必不可少的。

    因此,感兴趣的同学可以以本系列为入门,在掌握本系列所介绍的基础知识前提下掌握更多 python,psychopy 的方法,从而可以更好地应对不同的实验范式要求。

    6 系列课程的总结

    至此,我们已经学习了Psychopy入门数据类型与运算符条件与循环flanker范式的完整编程、实验数据的收集与处理。

    基本学完了 Python 在 Psychopy 中需要用到的大多数知识,虽然难度不是很大,但是比较繁杂,建议通过练习以熟悉这些基本的语句和方法。

    PS:本文首发于微信公众平台行上行下,微信后台回复关键词“psychopy第4期”即可获得所述的资料及代码啦!

    作者:阿槑
    排版:喵君姐姐

    参考文献:

    Eriksen, B. A., & Eriksen, C. W. (1974). Effects of noise letters upon the identification of a target letter in a nonsearch task. Perception & Psychophysics, 16(1), 143-149.
    在这里插入图片描述

    展开全文
  • AopLog是基于Spring Aop 和ThreadLocal实现一个专门对请求方法内容日志拦截与处理的日志工具包。 场景 : 我想知道一些重要请求方法请求参数,响应参数,请求头,以及耗时,方法是成功还是失败等等信息。 普通...

    AopLog是基于Spring Aop 和ThreadLocal实现的一个专门对请求方法内容日志的拦截与处理的日志工具包。

    场景 :

    1. 我想知道一些重要的请求方法的请求参数,响应参数,请求头,以及耗时,方法是成功还是失败等等信息。
    2. 普通的log.info或warn信息没有所属请求的上下关系,我不知道执行到哪一步发生了异常,并不方便查看和分析。
    3. 正式环境中,我并不想打印太多无意义的info日志(有些只是为了排查问题打印的日志),只希望在发生异常时记录日志。
    4. 日志的收集,我希望将这些请求的日志记录下来,记录方式我自己决定,比如正常的日志打印,常见的日志写入数据库,日志写入到文件,日志入队列等等。
    5. 整个日志的记录完全不干扰正常请求方法的流程,日志的收集处理异步化,不影响正常请求方法的性能与响应。
    6. 不想日后每个项目工程都写一份这样的Aop拦截处理日志的代码。

    快速开始

    项目通过maven的pom.xml引入

    
    <dependency>
        <groupId>com.github.ealenxie</groupId>
        <artifactId>aop-log</artifactId>
        <version>2.1</version>
    </dependency>
    
    

    或者通过gradle引入

    compile group: 'com.github.ealenxie', name: 'aop-log', version: '2.1'
    

    @AopLog注解使用,进行日志记录

    直接在类(作用类的所有方法)或类方法(作用于方法)上加上注解@AopLog,进行日志记录

    例如 :

    import com.github.AopLog;
    import name.ealen.infra.base.resp.RespBody;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author EalenXie create on 2020/6/22 14:28
     */
    @AopLog(type = "测试",stackTraceOnErr = true)
    @RestController
    public class AppController {
    
        @GetMapping("/app/sayHello")
        public RespBody<String> sayHello() {
            return RespBody.ok("hello EalenXie");
        }
    
    }
    
    

    自定义全局的日志收集器实现收集 LogCollector

    例如只是简单打印,或写入到库等等。

    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.github.LogData;
    import com.github.collector.LogCollector;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    
    /**
     * @author EalenXie create on 2020/9/15 13:46
     * 此为样例参考
     * 配置一个简单的日志收集器 这里只是做了一个log.info打印一下,可以在这里写入到数据库中或者写入
     */
    @Slf4j
    @Component
    public class AopLogCollector implements LogCollector {
        private ObjectMapper objectMapper = new ObjectMapper();
        @Override
        public void collect(LogData logData) {
            try {
                log.info(objectMapper.writeValueAsString(logData));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
    }
    

    配置@Component的全局日志收集器只能配置一个。

    接口调用 /say/hello 测试即可看看到控制台打印出结果 :

    2020-09-16 16:01:04.782  INFO 2012 --- [AsyncExecutor-2] name.ealen.infra.advice.AopLogCollector  : {"appName":"app-template","host":"127.0.0.1","port":8080,"clientIp":"192.168.110.1","reqUrl":"http://localhost:8080/app/sayHello","httpMethod":"GET","headers":{"User-Agent":"Apache-HttpClient/4.5.10 (Java/11.0.5)"},"type":"测试","content":"","method":"name.ealen.api.facade.AppController#sayHello","args":null,"respBody":{"code":"200","desc":"OK","message":"请求成功","dateTime":"2020-09-16 16:01:04","body":"hello EalenXie"},"logDate":1600243264780,"costTime":1,"threadName":"http-nio-8080-exec-3","threadId":33,"success":true}
    

    记录的日志对象LogData属性说明

    LogData 记录的内容

    字段 类型 注释
    appName String 应用名称
    host String 主机
    port int 端口号
    clientIp String 请求客户端的Ip
    reqUrl String 请求地址
    headers Object 请求头部信息(可选择记录) 默认记录user-agent,content-type
    type String 操作类型,默认值undefined
    content String 方法步骤内容,默认是空,可使用LogData.step进行内容步骤记录
    method String 请求的本地java方法
    args Object 方法请求参数
    respBody Object 方法响应参数
    costTime long 整个方法耗时
    logDate Date Log产生时间,LogData对象初始化的时间
    threadName String 线程名称
    threadId long 线程Id
    success boolean 执行状态,成功(true)/异常(false)

    AopLog 注解选项说明

    选项 类型 说明 默认
    logOnErr boolean 仅当发生异常时才记录收集 false
    type String 操作类型 默认值"undefined"
    headers String[] 记录的header信息 ,选择要记录哪些header信息 默认"User-Agent",“content-type”
    args boolean 是否记录请求参数 true
    respBody boolean 是否记录响应参数 true
    stackTraceOnErr boolean 当目标方法发生异常时,是否追加异常堆栈信息到LogData的content中 false
    asyncMode boolean 异步方式收集 true
    collector Class<? extends LogCollector> 指定日志收集器 默认不调整收集器,使用全局的日志收集器

    LogData的step方法。

    记录步骤。(如果某些重要步骤希望被记录下来)
    例如 :

    import com.github.AopLog;
    import com.github.LogData;
    import name.ealen.infra.base.resp.RespBody;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    
    /**
     * @author EalenXie create on 2020/6/22 14:28
     */
    @AopLog(type = "测试",stackTraceOnErr = true)
    @RestController
    public class AppController {
    
    
        @GetMapping("/app/sayHello")
        public RespBody<String> sayHello() {
            LogData.step("1. 第一步执行完成");
            //......
            LogData.step("2. 第二步执行完成");
            //.....
            LogData.step("3. service的方法执行完成");
            //.....
            return RespBody.ok("hello EalenXie");
        }
    
    }
    
    

    注意: 此方法如果不在被@AopLog注解的方法的整体调用链路中使用,则当前线程中的ThreadLocal中的LogData不会释放,需要手动调用LogData.removeCurrent();

    此时再次接口调用 /say/hello 测试即可看看到控制台打印出结果,重点观察content字段 :

    2020-09-16 17:26:20.285  INFO 3284 --- [AsyncExecutor-2] name.ealen.infra.advice.AopLogCollector  : {"appName":"app-template","host":"127.0.0.1","port":8080,"clientIp":"192.168.110.1","reqUrl":"http://localhost:8080/app/sayHello","httpMethod":"GET","headers":{"User-Agent":"Apache-HttpClient/4.5.10 (Java/11.0.5)"},"type":"测试","content":"1. 第一步执行完成\n2. 第二步执行完成\n3. service的方法执行完成\n","method":"name.ealen.api.facade.AppController#sayHello","args":null,"respBody":{"code":"200","desc":"OK","message":"请求成功","dateTime":"2020-09-16 17:26:20","body":"hello EalenXie"},"logDate":1600248380283,"costTime":1,"threadName":"http-nio-8080-exec-2","threadId":32,"success":true}
    

    关于

    开源Github地址 : https://github.com/EalenXie/aop-log

    感谢各位提出意见和支持。

    展开全文
  • 场景 :使用Spring Aop拦截参数日志目前大部分做法都基本上大同小异,不想日后每个项目工程都写一份这样Aop拦截处理日志代码,甚至代码侵入。我想知道一些相对重要请求方法请求参数,响应参数,请求头,以及内部...

    a4c09e7d9aab01bf38c346d4d368355d.png

    场景 :

    1. 使用Spring Aop拦截参数日志目前大部分做法都基本上大同小异,不想日后每个项目工程都写一份这样的Aop拦截处理日志的代码,甚至代码侵入。
    2. 我想知道一些相对重要的请求方法的请求参数,响应参数,请求头,以及内部耗时,方法是成功还是失败等等信息。发生错误时我也不知道执行到哪一步发生了异常,是不是某个参数导致出的逻辑问题。
    3. 普通的log.info或warn信息没有所属请求的上下关系,并不方便查看和分析。
    4. 正式环境中,我并不想打印太多无意义的info日志(有些只是为了排查问题打印的日志,程序正常运行时其实毫无意义),只希望在发生异常时记录日志或者只希望每次请求只记录一条关键的请求信息。
    5. 日志的收集,我希望将这些请求的日志记录下来,记录的实现方式我自己决定,比如正常的日志打印,常见的日志写入数据库,日志写入到文件,日志入队列等等。
    6. 整个日志的记录完全不干扰正常请求方法的流程,日志的收集处理异步化,完全不影响正常请求方法的性能与响应。
    7. 只需要通过@AopLog注解决定是否记录。

    快速开始

    项目通过maven的pom.xml引入

    <dependency>
        <groupId>com.github.ealenxiegroupId>
        <artifactId>aop-logartifactId>
        <version>2.2version>
    dependency>

    或者通过gradle引入

    compile group'com.github.ealenxie', name: 'aop-log', version: '2.2'

    @AopLog注解使用,进行日志记录

    直接在类(作用类的所有方法)或类方法(作用于方法)上加上注解@AopLog,进行日志记录

    例如 :

    import com.github.AopLog;
    import name.ealen.infra.base.resp.RespBody;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;

    /**
     * @author EalenXie create on 2020/6/22 14:28
     */

    @AopLog(type = "测试",stackTraceOnErr = true)
    @RestController
    public class AppController {

        @GetMapping("/app/sayHello")
        public RespBody sayHello() {
            return RespBody.ok("hello EalenXie");
        }

    }

    自定义全局的日志收集器实现收集 LogCollector

    例如只是简单打印,或写入到库等等。

    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.github.LogData;
    import com.github.collector.LogCollector;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;

    /**
     * @author EalenXie create on 2020/9/15 13:46
     * 此为样例参考
     * 配置一个简单的日志收集器 这里只是做了一个log.info打印一下,可以在这里写入到数据库中或者写入
     */

    @Slf4j
    @Component
    public class AopLogCollector implements LogCollector {
        private ObjectMapper objectMapper = new ObjectMapper();
        @Override
        public void collect(LogData logData) {
            try {
                log.info(objectMapper.writeValueAsString(logData));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
    }

    配置@Component的全局日志收集器只能配置一个。

    接口调用 /say/hello 测试即可看看到控制台打印出结果 :

    2020-09-16 16:01:04.782  INFO 2012 --- [AsyncExecutor-2] name.ealen.infra.advice.AopLogCollector  : {"appName":"app-template","host":"127.0.0.1","port":8080,"clientIp":"192.168.110.1","reqUrl":"http://localhost:8080/app/sayHello","httpMethod":"GET","headers":{"User-Agent":"Apache-HttpClient/4.5.10 (Java/11.0.5)"},"type":"测试","content":"","method":"name.ealen.api.facade.AppController#sayHello","args":null,"respBody":{"code":"200","desc":"OK","message":"请求成功","dateTime":"2020-09-16 16:01:04","body":"hello EalenXie"},"logDate":1600243264780,"costTime":1,"threadName":"http-nio-8080-exec-3","threadId":33,"success":true}

    记录的日志对象LogData属性说明

    「LogData 记录的内容」

    字段类型注释
    appNameString应用名称
    hostString主机
    portint端口号
    clientIpString请求客户端的Ip
    reqUrlString请求地址
    headersObject请求头部信息(可选择记录) 默认记录user-agent,content-type
    typeString操作类型,默认值undefined
    contentString方法步骤内容,默认是空,可使用LogData.step进行内容步骤记录
    methodString请求的本地java方法
    argsObject方法请求参数
    respBodyObject方法响应参数
    costTimelong整个方法耗时
    logDateDateLog产生时间,LogData对象初始化的时间
    threadNameString线程名称
    threadIdlong线程Id
    successboolean执行状态,成功(true)/异常(false)

    AopLog 注解选项说明

    选项类型说明默认
    logOnErrboolean仅当发生异常时才记录收集false
    typeString操作类型默认值"undefined"
    headersString[]记录的header信息 ,选择要记录哪些header信息默认"User-Agent","content-type"
    argsboolean是否记录请求参数true
    respBodyboolean是否记录响应参数true
    stackTraceOnErrboolean当目标方法发生异常时,是否追加异常堆栈信息到LogData的content中false
    asyncModeboolean异步方式收集true
    collectorClass extends LogCollector>指定日志收集器默认不调整收集器,使用全局的日志收集器

    LogData的step方法。

    记录步骤。(如果某些重要步骤希望被记录下来) 例如 :

    import com.github.AopLog;
    import com.github.LogData;
    import name.ealen.infra.base.resp.RespBody;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;


    /**
     * @author EalenXie create on 2020/6/22 14:28
     */
    @AopLog(type = "测试",stackTraceOnErr = true)
    @RestController
    public class AppController {


        @GetMapping("/app/sayHello")
        public RespBody sayHello() {
            LogData.step("1. 第一步执行完成");
            //......
            LogData.step("2. 第二步执行完成");
            //.....
            LogData.step("3. service的方法执行完成");
            //.....return RespBody.ok("hello EalenXie");
        }
    }

    此时再次接口调用 /say/hello 测试即可看看到控制台打印出结果,重点观察content字段 :

    2020-09-16 17:26:20.285  INFO 3284 --- [AsyncExecutor-2] name.ealen.infra.advice.AopLogCollector  : {"appName":"app-template","host":"127.0.0.1","port":8080,"clientIp":"192.168.110.1","reqUrl":"http://localhost:8080/app/sayHello","httpMethod":"GET","headers":{"User-Agent":"Apache-HttpClient/4.5.10 (Java/11.0.5)"},"type":"测试","content":"1. 第一步执行完成\n2. 第二步执行完成\n3. service的方法执行完成\n","method":"name.ealen.api.facade.AppController#sayHello","args":null,"respBody":{"code":"200","desc":"OK","message":"请求成功","dateTime":"2020-09-16 17:26:20","body":"hello EalenXie"},"logDate":1600248380283,"costTime":1,"threadName":"http-nio-8080-exec-2","threadId":32,"success":true}

    关于

    开源Github地址 : https://github.com/EalenXie/aop-log

    作者:风雪漫中州

    https://www.cnblogs.com/ealenxie/p/13685216.html

    a6a0291d507a06f109208af63c2fe313.png

    展开全文
  • 基于IPV6的交通事故信息收集系统的设计实现,张晓东,李茹,道路上的车辆越来越多,交通事故的发生率也越来越高,交通事故的频繁发生给交通部门处理事故带来了一定的压力。传统的收集交通事
  • 用于解析/ proc以获得系统信息的工具包 注意:该工具仍处于早期阶段,缺少一些功能或功能不完全的组件,这些组件将在以后的推送中添加。 目的 该工具包的最初目的是创建接近bash的核心功能脚本,以解析/proc中的数据...
  • 当后台使用springboot方式开发,然后打包成jar包,使用java -jar 命令部署时,需要保留日志信息,并且随着时间增长日志不能过大,需要进行分割处理, 当然日志总量也有限制,需要定期清除。 二、解决方法 在...

    一、场景

    当后台使用springboot方式开发,然后打包成jar包,使用java -jar 命令部署时,需要保留日志信息,并且随着时间的增长日志不能过大,需要进行分割处理,

    当然日志总量也有限制,需要定期清除。

     

    二、解决方法

    在脚本中使用命令行在后台运行jar, 然后将输出重定向到文件中。使用定时任务,每天在固定时间进行日志转移分割,并且检测清除超过时间范围的日志文件。

     

    启动jar

    #!/bin/bash

    #jar名称

    JAR_NAME=blade_apppack.jar

    LOG_PATH=service.log

    tips() {

            echo ""

            echo "WARNING!!!......Tips, please use command: sh auto_service.sh [start|stop|restart|status].   For example: sh auto_service.sh start  "

            echo ""

            exit 1

    }

    start() {

            # 重新获取一下pid,因为其它操作如stop会导致pid的状态更新        

            pid=`ps -ef | grep $JAR_NAME | grep -v grep | awk '{print $2}'`

            # -z 表示如果$pid为空时执行

            if [ -z $pid ]; then

                nohup java -jar /Users/xxx/PackOnline/backEndDeploy/$JAR_NAME > /Users/xxx/PackOnline/backEndDeploy/backEndLog/$LOG_PATH 2>&1 &

                pid=`ps -ef | grep $JAR_NAME | grep -v grep | awk '{print $2}'`

                echo ""

                echo "Service ${JAR_NAME} is starting!pid=${pid}"

                echo "........................Start successfully!........................."

        else

                echo "" 

                echo "Service ${JAR_NAME} is already running,it's pid = ${pid}. If necessary, please use command: sh auto_service.sh restart."          

                echo ""

        fi

    }

    stop() {

            # 重新获取一下pid,因为其它操作如start会导致pid的状态更新       

            pid=`ps -ef | grep $JAR_NAME | grep -v grep | awk '{print $2}'`

            # -z 表示如果$pid为空时执行。 注意:每个命令和变量之间一定要前后加空格,否则会提示command找不到 

            if [ -z $pid ]; then

            echo ""        

            echo "Service ${JAR_NAME} is not running! It's not necessary to stop it!"               

            echo "" 

            else

            kill -9 $pid

            echo ""         

            echo "Service stop successfully!pid:${pid} which has been killed forcibly!"            

            echo "" 

            echo "" > $LOG_PATH

            fi

    }

    # 输出运行状态方法

    status() {

             # 重新获取一下pid,因为其它操作如stop、restart、start等会导致pid的状态更新     

             pid=`ps -ef | grep $JAR_NAME | grep -v grep | awk '{print $2}'`

              # -z 表示如果$pid为空时执行。注意:每个命令和变量之间一定要前后加空格,否则会提示command找不到        

              if [ -z $pid ];then

              echo ""        

              echo "Service ${JAR_NAME} is not running!"            

              echo ""       

              else

              echo ""        

              echo "Service ${JAR_NAME} is running. It's pid=${pid}"                

              echo ""       

              fi

    }

    # 重启方法

    restart() {

            echo "" 

            echo ".............................Restarting.............................."    

            echo "....................................................................."            

            # 重新获取一下pid,因为其它操作如start会导致pid的状态更新       

            pid=`ps -ef | grep $JAR_NAME | grep -v grep | awk '{print $2}'`

            # -z 表示如果$pid为空时执行。 注意:每个命令和变量之间一定要前后加空格,否则会提示command找不到 

            if [ ! -z $pid ]; then

            kill -9 $pid

            fi

            start

            echo "....................Restart successfully!..........................."

    }

    # 查看日志

    logs(){

          # 输出实时日志

         tail -n 100 -f /Users/xxx/PackOnline/backEndDeploy/backEndLog/$LOG_PATH

    }

     

    # 根据输入参数执行对应方法,不输入则执行tips提示方法

    case "$1" in

            "start")

                    start

                    ;;

            "stop")

                    stop

                     ;;

            "status")

                    status

                    ;;

            "restart")

                    restart

                    ;;

            "logs")

                    logs

                    ;;

             *)

                    tips

                    ;;

    esac

    nohup 使用参考 https://www.cnblogs.com/baby123/p/6477429.html

     

    定时任务开启

    运行crontab -e 命令, 加入如下cron 任务,每天23:00 执行

    0 23 * * * sh /Users/xxx/PackOnline/backEndDeploy/crontab.sh

    #拷贝,将当日的日志拷贝到按照时间命名的文件中

    cp /Users/xxx/PackOnline/backEndDeploy/backEndLog/service.log  /Users/xxx/PackOnline/backEndDeploy/backEndLog/`date "+%Y-%m-%d-%H-%M-%S"`_apppack.log

    #清空, 将日志文件内容清空,不能删除文件,否则原先的日志输出无法找到对象

    echo "" > /Users/hongboni/PackOnline/backEndDeploy/backEndLog/service.log

    #检查7天前的文件进行删除

    find /Users/hongboni/PackOnline/backEndDeploy/backEndLog -mtime +7 -name "*apppack.log" -exec rm {} \;

    关于find 命令按照时间找文件可参考如下图理解:

     

    -ctime -n    查找距现在 n*24H 内修改过的文件
    -ctime n    查找距现在 n*24H 前, (n+1)*24H 内修改过的文件
    -ctime +n    查找距现在 (n+1)*24H 前修改过的文件

     

    ---(+n)----------|----------(n)----------|----------(-n)---

    (n+1)*24H前| (n+1)*24H~n*24H间 |n*24H内

    展开全文
  • 实体识别是信息提取、问答系统、句法分析、机器翻译等应用领域重要基础工具,作为结构化信息提取重要步骤。 应用场景:各大手机厂商语音助手 以分词和词性标注为基础,分析语音命令中关键名词、动词、数量、...
  • 他们还必须制定指南,说明在达到收集信息的最初目的后,或者在用户最后一次公司接触后的三年内(以先发生的为准),这些数据将如何销毁。 为了合法获得生物特征数据,私人公司必须以书面形式通知当事人收集和存储...
  • EOI(end of Interrupt):发送给可编程中断控制器信号,指示当前中断已经处理完成。EOI信号在中断回调函数处理完成是被发送,或者PIC能够发送一个auto-Eoi在启动中断回调处理时。 APIC & 8259A X86计算机...
  • 简介敏感信息收集 想起了道哥名言,人才是最大漏洞,今天儿终于学到传说中非常神奇社工了,之前看电影中其实有很多取材于真实手段,比如针对垃圾处理不完全进行复原破解利用; 平时也看过很多社工案例,...
  • [size=medium]1.网上得数据下载到本地,利于快速分析 具体操作:java多线程 httputil ...3.建立第二部中提取key值开发系统设计key值关系规则 4.导入数据库,建立持续自动更新机制,跟系统集成话就quar...
  •  个人信息保护法规范主体除了收集收集者,还应当增加基础软件和硬件厂商等可能对个人信息收集产生重大影响机构。  如果只做境外立法比较研究,个人信息保护法似乎规范主体就是收集者(处理者、控制者...
  • [本文出自天外归云博客园] ...在运行脚本时,对脚本异常要有捕捉,并把捕捉到的信息打到日志中去。在lib文件夹中添加write_log.py文件,内容如下: # -*- coding: utf-8 -*- import os impo...
  • 个人收集整理资料 仅供交流学习 勿作商业用途 信息与通信工程学院 信号与信息处理综合实验报告 部分 班级 姓名 学号 序号 实验三用 FPGA实现快速傅里叶变换 个人收集整理资料 仅供交流学习 勿作商业用途 一 实验目的...
  • 其通过创建庞大煤矿数据系统收集各类生产资料,同时利用数据挖掘技术对煤矿产量进一步分析研究,为企业煤矿生产提供科学指导依据。文章主要分析了煤矿生产中计算机数据挖掘机产品分析相关问题。
  • 作为产品经理,需要处理很多信息,常见有需求收集阶段获取调查、调研结果数据,日常用户反馈数据,数据分析报表,数据挖掘,各种网络文章、评论、论坛上资讯以及网络上搜索引擎可以挖出来所有关于自身所...
  • 在互联网迅猛发展的今天 各大厂发挥十八般武艺的收集用户的各种信息,甚至包括点击的位置,我们也经常发现自己刚搜完一个东西,再打开网页时每个小广告都会出现之相关联的商品或信息,在感叹智能的同时不惊想 什么...
  • 因此,将处理废水洪水和基础流水分开,以保证有更高质量水可用于更高质量用途,例如饮用或娱乐。 这项研究重点是安曼西部和西北部Kafrain和Shueib流域建造水坝。 使用遥感,地理信息系统(GIS)和...
  • 语言是人类特有的特征,而人声是常用的工具,也是相互传递信息的重要途径。语音具有较大的信息容量。因此,我们可以用现代的方法来研究语音处理技术,使人们能够方便地传输、存储、访问和应用语音。 在本论文中,...
  • 计算机处理的信息更多时候不是数值而是字符串,正则表达式就是在进行字符串匹配和处理的时候最为强大工具 2、Java中是如何支持正则表达式操作。 Java中String类提供了支持正则表达式操作方法,包括:...
  • 2019年公文写作与处理的经典习题 公文写作,是指公务文书写作,是文件拟稿工作, 它是机关制发文件第一个工作环节。今天小编整理就是关于公文写作习题。希望大家能在考试中通过,取得优异成绩! 20xx年...
  • 并将其双ferry节点同向运动从理论上进行了分析比较, 证明逆向运动提高了ferry节点携带能力, 降低了信息延时, 进而提高网络传输能力, 仿真结果也证明了这一点。  1引言  1. 1无线传感器网络介绍  在无线...
  • 在互联网迅猛发展的今天 各大厂发挥十八般武艺的收集用户的各种信息,甚至包括点击的位置,我们也经常发现自己刚搜完一个东西,再打开网页时每个小广告都会出现之相关联的商品或信息,在感叹智能的同时不惊想 什么...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,148
精华内容 859
关键字:

信息的收集与处理