🕰️

[Jenkins] 特定の時間に動いていたビルドを探す

2022/09/27に公開

今いま問題が起きている場合は

とりあえずトップページから実行中のビルドを探せば良いのですが

過去の時点で実行中だったビルドを探すのは難しい

ユーザーに聞いて回るのは手間ですし不正確
かと言って、ビルドページを一つひとつ開いて確認するなんて非効率過ぎる。。

CIAnalyzerと簡単なスクリプトで解析する

ビルド情報を取得する

Jenkinsのビルド情報をJSON形式で引っこ抜いてきてくれる便利ツールがあるので、これを使いましょう。
https://github.com/Kesin11/CIAnalyzer

git clone https://github.com/Kesin11/CIAnalyzer.git
cd CIAnalyzer
vim ci_analyzer.yaml

baseUrlは自分のJenkinsに合わせて変更してください。

ci_analyzer.yaml
jenkins:
  baseUrl: https://localhost:8080
  correctAllJobs: # Enable correct all pipeline jobs
    filterLastBuildDay: 30 # Filter by last build day. default: 30
    isRecursively: true # Also collect jobs under folders. default: false
  jobs: []
  exporter: &exporter
    local:
      outDir: output # default: output
      format: json # default: json. 'json' and 'json_lines' are supported.
  lastRunStore:
    backend: local
    path: .ci_analyzer/last_run/jenkins.json

いよいよ、ビルド情報を取得します。

export JENKINS_USER=admin
export JENKINS_TOKEN=***

docker run \
  --mount type=bind,src=${PWD},dst=/app/ \
  -e JENKINS_USER=${JENKINS_USER} \
  -e JENKINS_TOKEN=${JENKINS_TOKEN} \
  ghcr.io/kesin11/ci_analyzer:v5.1 -c ci_analyzer.yaml

outputフォルダ下にビルド情報が格納されているはずです。

ビルド情報を解析する

Elasticsearch等を使っても良いのですが、データ量がそんなに無いうちはインメモリーのSQLiteでサクッと解析するのが楽です。

analyze.py
import sys, json, sqlite3

########################
# Validation
########################
if len(sys.argv) < 3:
    print('Usage: python analyze.py /path/to/json problematicTime')
    sys.exit(1)

########################
# Initialization
########################
data_path = sys.argv[1]
data = None

problematicTime = sys.argv[2]

con = sqlite3.connect(':memory:')
cur = con.cursor()
# Create table
cur.execute('''CREATE TABLE jenkins (id text primary key, job text, duration real, startedAt text, completedAt text)''')

########################
# Insert data
########################
with open(data_path) as json_file:
    data = json.load(json_file)

for d in data:
    workflowRunId       = d.get("workflowRunId")
    workflowName        = d.get("workflowName")
    workflowDurationSec = d.get("workflowDurationSec")
    workflowStartedAt   = d.get("startedAt")
    workflowCompletedAt = d.get("completedAt")

    if not (workflowRunId and workflowName and workflowDurationSec and workflowStartedAt and workflowCompletedAt):
        continue

    duration = int(workflowDurationSec)

    # Insert a row of data
    cur.execute("INSERT INTO jenkins VALUES ('{}', '{}', {}, '{}', '{}')".format(workflowRunId, workflowName, duration, workflowStartedAt, workflowCompletedAt))

# Save (commit) the changes
con.commit()

########################
# Analyze data
########################
print('Job running at {}'.format(problematicTime))
for row in cur.execute("SELECT id, startedAt, completedAt FROM jenkins WHERE startedAt < '{}' AND completedAt > '{}'".format(problematicTime, problematicTime)):
    print('Build: "{0[0]}" - started at {0[1]} completed at {0[2]}'.format(row))

# We can also close the connection if we are done with it.
# Just be sure any changes have been committed or they will be lost.
con.close()

SQLiteは賢いのでWHERE句の大小比較で時間を絞り込めます。

python analyze.py output/20220927-1021-workflow-jenkins.json '2022-09-27T09:00'
Job running at 2022-09-27T09:00
Build: "jenkins-JOB_NAME-1" - started at 2022-09-27T08:56:28.014Z completed at 2022-09-27T09:05:50.208Z

jenkinsは接頭語ですので、その後ろのJOB_NAMEが疑わしいジョブ名、そしてその後ろの数字がビルド番号です。

ビルドの実行者もしくはジョブの設定者に突撃する

問題があるジョブは、そっとDisableにすることをお勧めします。

Discussion