如何从 CSV 测试结果文件中删除斜坡期间的测试结果?

如何从 CSV 测试结果文件中删除斜坡期间的测试结果?

我在 CSV 文件中有一些测试结果。第一个字段有时间戳,以毫秒为单位

以下是 CSV 文件中的示例记录:

1628689875326,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17

我想删除加速期间(从开始时间起 5 分钟)和减速期间(最后 5 分钟)的测试结果,并将过滤后的测试结果写入 CSV 文件。

我尝试使用硬编码值

#!/usr/bin/awk -f

  BEGIN {
    endTime=1628689875326
    startTime=1628689875326-300*1000
    offset=1628689875326-3900*1000

    FS=","
    rowCount=0
  }
  {

    if ($1> startTime && $1<offset){
        rowCount++
        print $0
    }
  }

答案1

不要使用 shebang 调用 awk,而是使用 shebang 调用 shell,然后调用 awk。看https://stackoverflow.com/a/61002754/1745001为什么。

我会这样做你想做的事:

#!/usr/bin/env bash

awk -F',' '
    NR==FNR {
        if (NR==2) {
            fiveMins = 5*60*1000*1000
            begTime  = $1 + fiveMins
        }
        endTime = $1 - fiveMins
        next
    }
    (FNR==1) || ( (begTime <= $1) && ($1 <= endTime) ) {
        print
        rowCount++
    }
    END {
        print rowCount+0 | "cat>&2"
    }
' "$1" "$1"

或者您可以通过使用从最后一行获取时间戳tail(灵感来自@格林在线的回答) 而不是在 awk 中读取文件两次:

#!/usr/bin/env bash

awk -v lastTime="$(tail -n 1 "$1" | cut -d',' -f1)" -F',' '
    NR==2 {
        fiveMins = 5*60*1000*1000
        begTime  = $1 + fiveMins
        endTime  = lastTime - fiveMins
    }
    (NR==1) || ( (begTime <= $1) && ($1 <= endTime) ) {
        print
        rowCount++
    }
    END {
        print rowCount+0 | "cat>&2"
    }
' "$1"

无论哪种方式,你都可以将其称为:

scriptname input.csv > output.csv

> output.csv或者如果您不介意对输出文件名进行硬编码,则在 shell 脚本中的 awk 脚本后面添加。

上面假设您的 CSV 有一个您想要在输出中打印的标题行。

请注意,通过不使用 shebang 调用 awk,我可以使用 shell 来做它最擅长的事情,即调用其他命令并多次使用脚本参数,然后调用 awk 来做它最擅长的事情,即处理文本、引导比其他方式更简洁、更健壮、更高效的脚本。

答案2

硬编码解决方案

在您的硬编码时间脚本中,这是问题所在:

  • offset小于startTime,因此if条件

    $1> startTime && $1<offset
    

    绝不是真实的。

原因是startTime距离结束还有 5 分钟(5*60= 300 秒),但offset距离结束还有 65 分钟(65*60= 3900 秒)。

解决方案是将初始化程序更改为

    startTime=1628689875326-3900*1000*1000
    offset=1628689875326-300*1000*1000

这会将相关时间设置为

endTime = 1628689875326
startTime = endTime - (3900*1000*1000) =  1624789875326
5 minutes before end = endTime - (300*1000*1000)  = 1628389875326

所以,现在,给定一个像这样的日志文件

1624789875326,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17
1624789875327,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17
1628389875325,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17
1628389875326,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17
1628389875327,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17
1628689875326,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17

跑步

more test.log | ./filter.awk

给出所需的结果

1624789875327,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17
1628389875325,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17

更好的解决方案 - 获取开始时间

然而,进一步检查你的问题表明,有一些事情定义不明确:

  • 在您的脚本中,您的startTime可能是过滤器的开始,而不是实际日志的开始。日志的开始时间将提前五分钟,即

    1624789875326 - 300*1000*1000 = 1624489875326
    
  • 你说时间以毫秒为单位,但你使用*1000*1000,这意味着微秒

尽管如此,这里有一个解决方案,它将自动查找启动时间(从日志文件的第一行开始)并计算斜坡时间,从而计算过滤器的启动时间。

它还将计算过滤时间的结束(与硬编码脚本相同的方式) -尽管您仍然需要输入结束时间,即日志中的最后一个时间戳。

#!/usr/bin/awk -f
  
  BEGIN {
    rampTimeMins=5
    rampTimeMillis=rampTimeMins*60*1000
    rampTimeMicros=rampTimeMins*60*1000*1000

    # Enter the start time
    # (not required, if NR conditional is used)
    startTime=0
    # Calculate Start filter time in microseconds 
    # (not required, if NR conditional is used)
    filterStartTime=startTime+rampTimeMicros

    # Enter the end time (required)
    endTime=1628689875326
    # Calculate End filter time in microseconds
    filterEndTime=endTime-rampTimeMicros

    FS=","
    rowCount=0
  }

  {
    if (NR==1){
      startTime=$1
      filterStartTime=startTime+rampTimeMicros
    }
    if ($1> filterStartTime && $1<filterEndTime){
      rowCount++
      print $0
    }
  }

  END {
    print rowCount
  }

注1:如果您的 CSV 第一行是标题,则更NR==1改为NR==2

笔记2:如果你想使用毫秒而不是微秒,只需更改rampTimeMicrosrampTimeMillis

这是一个示例日志文件,其中包含额外的Early time,即日志的实际开始时间(而不是过滤器的开始时间)

1624489875326,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17
1624489875327,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17
1624789875326,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17
1624789875327,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17
1628389875325,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17
1628389875326,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17
1628389875327,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17
1628689875326,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17

与哪个运行

more test.log | ./filter.awk

给出与之前相同的结果

1624789875327,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17
1628389875325,327,3.1 HTTP Request /api/StaffPortal,200,OK,Concurrency Thread Group   SignIn-ThreadStarter 1-5,text,true,,73018,17,17
2

但有额外的行数。


最终解决方案 - 获取结束时间

如果你改变线路

    endTime=1628689875326

    "tail -1 test.log | cut -d, -f1" | getline endTime

然后脚本不需要进一步编辑,因为获得了最后的时间戳脚本运行。制作是通用用途

    "tail -1 "ARGV[1]" | cut -d, -f1" | getline endTime

或者更好的是(为了安全起见)将带引号的文件名传递给生成的子 shell,按照艾德的评论:

更改"tail -1 "ARGV[1]""tail -1 \047"ARGV[1]"\047,这样您就不会将文件名传递给不带引号的生成的子shell(所有这些都意味着通配,分词,安全等)

其中\047是单引号(FWIW:\042是双引号)),所以:

"tail -1 \047"ARGV[1]"\047 | cut -d, -f1" | getline endTime

所以最终的脚本就变成了

#!/usr/bin/awk -f
  
  BEGIN {
    rampTimeMins=5
    rampTimeMillis=rampTimeMins*60*1000
    rampTimeMicros=rampTimeMins*60*1000*1000

    # Enter the start time
    # (not required, if NR conditional is used)
    startTime=0
    # Calculate Start filter time in microseconds 
    # (not required, if NR conditional is used)
    filterStartTime=startTime+rampTimeMicros

    # Derive the end time
    "tail -1 \047"ARGV[1]"\047 | cut -d, -f1" | getline endTime
    # Calculate End filter time in microseconds
    filterEndTime=endTime-rampTimeMicros

    FS=","
    rowCount=0
  }

  {
    if (NR==1){
      startTime=$1
      filterStartTime=startTime+rampTimeMicros
    }
    if ($1> filterStartTime && $1<filterEndTime){
      rowCount++
      print $0
    }
  }

  END {
    print rowCount
  }

注1:如果您的 CSV 第一行是标题,则更NR==1改为NR==2

使用以下命令运行脚本 ( filter.awk)

./filter.awk test.log

不是

more test.log | ./filter.awk

参考:

答案3

通过以下修改更新了给定的示例脚本。

  1. 根据输入文件第二行中的开始时间计算filterStartTimefilterEndTime
  2. 将输出写入文件以供进一步分析
#!/usr/bin/awk -f
  BEGIN {
    testDurationMins=60
    rampTimeMins=5
    outputFileName="test-result-filtered-without-rampup.jtl"

    rampTimeMillis=rampTimeMins*60*1000

    # Enter the start time
    # (not required, if NR conditional is used)
    startTime=0
    # Calculate Start filter time in milliseconds
    # (not required, if NR conditional is used)
    filterStartTime=startTime+rampTimeMillis

    # Filter end time
    filterEndTime=0

    # Calculate the test duration  in milliseconds
    testDurationMillis=testDurationMins*60*1000

    FS=","
    rowCount=0
  }
  {

    if (NR==1){
      #Write header to the output file
      print > outputFileName
    }
    if (NR==2){
      #Set the filter start and end times
      startTime=$1
      filterStartTime=startTime+rampTimeMillis
      filterEndTime=filterStartTime+testDurationMillis
    }
    if (NR>2 && $1> filterStartTime && $1<filterEndTime){
      rowCount++
      print >> outputFileName
    }
  }
  END {
    print "" rowCount
  }

相关内容