How to parse Access Log in Jira for audit purposes
Platform notice: Server and Data Center only. This article only applies to Atlassian products on the Server and Data Center platforms.
Support for Server* products ended on February 15th 2024. If you are running a Server product, you can visit the Atlassian Server end of support announcement to review your migration options.
*Except Fisheye and Crucible
Summary
The access logs register information about all HTTP requests made to Jira, such as the IP from where it originated, the user that ran the request (if not anonymous), what is the method and endpoint utilized, and what was the HTTP response code.
These logs will include both requests made through APIs and through the browser UI, so they can be especially useful for audit purposes and to identify rogue automation processes.
This article explains how to interpret the entries from the Access Logs, and offers examples on how to parse Jira Tomcat's access log to audit user operations like browsing issues, performing searches, editing issues, etc.
Each operation in Jira results in several access logs entries — and it's expected to do so — so this article filters them down to a single line you can use for each operation.
The default location for the Tomcat access logs is
$JIRA-INSTALL/logs/
and they're named 'access_log.yyyy-mm-dd'
.
Environment
The log parsing examples on this page have been extracted from Jira 8.5.
Log parsing is an ad-hoc approach to auditing, and log messages can change from one version to another without public notice. If you implement this approach, make sure to include this log parsing validation when upgrading Jira in your QA/UAT environments.
Solution
Interpreting the logs
We've talked a bit about what the access logs are, now here's an example of what a login action looks like in them: All IPs used on the below example are fictional and are only meant to assist in the understanding of the logs.
10.61.175.127 654x34x1 sysadmin [04/Feb/2022:10:54:12 -0300] "POST /rest/gadget/1.0/login HTTP/1.1" 200 223 607 "https://jiratest/secure/Dashboard.jspa" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36" "51cumq"
At first, it may appear to be difficult to interpret them, but they can be broken down like so:
Origin IP | Request ID | Username | Timestamp | Method & Endpoint | HTTP status code | Bytes sent | Time Taken to process the request in millis | Accessed URL | Client utilized | Session ID |
---|---|---|---|---|---|---|---|---|---|---|
10.61.175.127 | 654x34x1 | sysadmin | [04/Feb/2022:10:54:12 -0300] | "POST /rest/gadget/1.0/login HTTP/1.1" | 200 | 223 | 607 | https://jiratest/secure/Dashboard.jspa | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36" | 51cumq |
The above is the default logging pattern shipped with Jira which is set by the "org.apache.catalina.valves.AccessLogValve" valve inside of the '$JIRA-INSTALL/conf/server.xml'
file.
Reference: Tomcat - Class AccessLogValve
Based on the above details, we can see that this was a successful login, for the sysadmin user, through a browser client, that came from the IP address 10.61.175.127.
For comparison, here's an example of how a failed API request to create a new user session, and a successful request to add comments in Jira look like respectively:
10.61.175.128 1169x56417x1 - [11/Jul/2021:19:29:49 -0700] "POST /rest/auth/1/session HTTP/1.1" 403 20816 46 "-" "Apache-HttpClient/4.5.5 (Java/1.8.0_202)" "1dl1546"
10.61.175.129 187x549578x1 restuser [27/Aug/2021:03:07:11 -0400] "POST /rest/api/2/issue/JRA-1750/comment HTTP/1.1" 201 737 169 "-" "python-requests/2.26.0" "1nnznnq"
Note the different client sources and HTTP response codes.
Parsing the logs
The regular expressions (regexp) below are written for Linux grep command. You may need to rewrite them to fit your particular environment or tool syntax.
The examples were captured from a local instance (localhost:50805) on a MacOS and with Jira user admin
.
If you're looking for performance analysis through access logs, consider the Jira Access Log Analyzer tool, instead.
Issues viewed
These don't include Issue data viewed from a Filter result (data in the columns).
Action | View an issue (from the issue view page, an agile board, or a Jira Service Management Queue) |
---|---|
Regex | GET.*?IssueEditAction.*?issueId= |
Example | 0:0:0:0:0:0:0:1 1002x168x2 admin [27/Apr/2020:16:42:47 -0300] "GET /secure/AjaxIssueEditAction!default.jspa?decorator=none&issueId=10201&_=1588016566691 HTTP/1.1" 200 4492 785 "http://localhost:50805/browse/ISSUE-2" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36" "ty3j4f" |
Action | Browse specific issue key (from the issue view page) |
---|---|
Regex | GET.*?/browse/<issue_key> (replace <issue_key> with the issue key) |
Example | 0:0:0:0:0:0:0:1 682x154x1 admin [03/Feb/2022:11:22:40 -0300] "GET /browse/SCRUM-13 - HTTP/1.1" 200 23950 4357 "http://localhost:48202/j8202/secure/Dashboard.jspa" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36" "17kwphk" |
Action | Browse issue on an agile Board |
---|---|
Regex | GET.*?details\.json.*?issueIdOrKey= |
Example | 0:0:0:0:0:0:0:1 768x1187x1 admin [17/Apr/2020:12:48:58 -0300] "GET /rest/greenhopper/1.0/xboard/issue/details.json?rapidViewId=1&issueIdOrKey=ISSUE-2&loadSubtasks=true&_=1587138364079 HTTP/1.1" 200 6853 155 "http://localhost:50805/secure/RapidBoard.jspa?rapidView=1&view=planning&selectedIssue=ISSUE-1&issueLimit=100" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36" "1isvqq2" |
Issues searched
Action | Quick search (top banner) |
---|---|
Regex | GET /rest/quicksearch |
Example | 0:0:0:0:0:0:0:1 1019x1106x1 admin [28/Apr/2020:16:59:27 -0300] "GET /rest/quicksearch/1.0/productsearch/search?q=ISSUE-1&_=1588103943271 HTTP/1.1" 200 376 35 "http://localhost:50805/issues/?jql=text%20~%20%22er%22" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36" "1tzzto7" |
Action | Issue search |
---|---|
Regex | POST /secure/QueryComponent\!Jql\.jspa |
Example | 0:0:0:0:0:0:0:1 1029x1139x1 admin [28/Apr/2020:17:09:16 -0300] "POST /secure/QueryComponent!Jql.jspa HTTP/1.1" 200 3284 24 "http://localhost:50805/issues/?jql=" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36" "1tzzto7" |
Bulk editions
Action | Bulk edit (actually execute the bulk operation after confirmation) |
---|---|
Regex | POST /secure/views/bulkedit/BulkEditPerform\.jspa |
Example | 0:0:0:0:0:0:0:1 1041x1610x1 admin [28/Apr/2020:17:21:02 -0300] "POST /secure/views/bulkedit/BulkEditPerform.jspa HTTP/1.1" 302 - 5 "http://localhost:50805/secure/views/bulkedit/BulkEditDetailsValidation.jspa" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36" "m2k0ih" |
CSV import
Action | Import Issues through CSV (bulk create Issues) |
---|---|
Regex | POST /secure/BulkCreateValueMappingPage.jspa POST /secure/admin/BulkCreateValueMappingPage.jspa |
Example | 10.10.10.10 830x795999x09 username [17/Jan/2024:13:43:16 -0300] "POST /secure/BulkCreateValueMappingPage.jspa?externalSystem=com.atlassian.jira.plugins.jira-importers-plugin%3AbulkCreateCsv HTTP/1.1" 302 - 9 "https://localhost:50805/secure/BulkCreateValueMappingPage!default.jspa?externalSystem=com.atlassian.jira.plugins.jira-importers-plugin:bulkCreateCsv" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/10.10.10.10 Safari/537.36 Edg/10.10.10.10" "m2k0ih" |
The /admin/ endpoint is used when an Admin performs the CSV import.
Filter result export
Action | Export filter results |
---|---|
Regex | GET /sr/jira.issueviews:searchrequest |
Example | 0:0:0:0:0:0:0:1 1014x392x1 admin [27/Apr/2020:16:54:24 -0300] "GET /sr/jira.issueviews:searchrequest-html-current-fields/temp/SearchRequest.html?jqlQuery=project+%3D+%22Service+Desk+1%22 HTTP/1.1" 200 1897 289 "http://localhost:50805/issues/?jql=project%20%3D%20%22Service%20Desk%201%22" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36" "bxjblo" 0:0:0:0:0:0:0:1 1014x394x1 admin [27/Apr/2020:16:54:59 -0300] "GET /sr/jira.issueviews:searchrequest-xml/temp/SearchRequest.xml?jqlQuery=project+%3D+%22Service+Desk+1%22&tempMax=1000 HTTP/1.1" 200 2370 323 "http://localhost:50805/issues/?jql=project%20%3D%20%22Service%20Desk%201%22" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36" "bxjblo" 0:0:0:0:0:0:0:1 1015x412x1 admin [27/Apr/2020:16:55:17 -0300] "GET /sr/jira.issueviews:searchrequest-word/temp/SearchRequest.doc?jqlQuery=project+%3D+%22Service+Desk+1%22&tempMax=1000 HTTP/1.1" 200 20222 212 "http://localhost:50805/issues/?jql=project%20%3D%20%22Service%20Desk%201%22" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36" "bxjblo" 0:0:0:0:0:0:0:1 576x876x1 admin [28/Apr/2020:09:36:23 -0300] "GET /sr/jira.issueviews:searchrequest-csv-current-fields/temp/SearchRequest.csv?jqlQuery=updated+%3E+-5d&delimiter=, HTTP/1.1" 200 326 19 "http://localhost:50805/issues/?jql=updated%20%3E%20-5d" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36" "1tzzto7" |
Issue Comments
Jira does't keep track of comment editions, and these access log patterns can help identify who edited a comment first or last, though it doesn't reveal the comment contents.
JRASERVER-12400 - Need ability to see change history of edited comments
Action | Edit a Comment (load the Edit Comment Screen) |
---|---|
Regex | GET /jira/secure/EditComment |
Example | 127.0.0.1 864x608x1 admin [10/May/2023:14:24:39 +0000] "GET /jira/secure/EditComment!default.jspa?id=10101&commentId=10201&inline=true&decorator=dialog&_=1683727396934 HTTP/1.1" 200 2174 48 "https://jira-base-url/browse/COMM-2" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36" "khfl3g" |
Access Log data | The matching line reveals the Comment Id (commentId=10201) and the Issue Id (id=10101) that were edited. |
Action | Edit a Comment (save the edited Comment) |
---|---|
Regex | POST /jira/secure/EditComment |
Example | 127.0.0.1 864x610x1 admin [10/May/2023:14:24:44 +0000] "POST /jira/secure/EditComment.jspa HTTP/1.1" 200 86 111 "https://jira-base-url/browse/COMM-2" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36" "khfl3g" |
Action | Add a new Comment |
---|---|
Regex | POST /jira/rest/api/2/issue/[A-Za-z0-9_\-]+/comment |
Example | 127.0.0.1 865x619x1 admin [10/May/2023:14:25:29 +0000] "POST /jira/rest/api/2/issue/COMM-2/comment HTTP/1.1" 201 393 128 "https://jira-base-url/browse/COMM-2" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36" "1ckbhbs" |
Attachments
Action | Upload a file from the Jira issue view |
---|---|
Regex |
|
Example | 127.0.0.1 853x1115x1 admin [24/Aug/2023:14:13:30 -0300] "POST /j980/rest/internal/2/AttachTemporaryFile?filename=002345-1-3.PDF&size=118974&atl_token=BXUJ-2Q9H-9TBS-PIHO_9b1fb48b841564b51996285372c9bbbba757578a_lin&formToken=&issueId=10142 HTTP/1.1" 201 136 37 "http://localhost:8980/j980/browse/ITSM-43" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/116.0" "gnclug" |
Action | Download an attachment file from the Jira issue view |
---|---|
Regex | GET .*secure/attachment/\d+ |
Example |
|
Action | Download or preview an attachment from the Jira issue view |
---|---|
Regex | GET .*secure/attachment/\d+ |
Example |
|
Action | Access the thumbnail of an image from the Jira issue view |
---|---|
Regex | GET .*secure/thumbnail/\d+ |
Example |
|
Action | Upload a file from the Customer Portal |
---|---|
Regex | POST .*servicedesk/customer/comment/tempfile\?filename= |
Example |
|
Action | Accessing the thumbnail of an image from the Customer Portal |
---|---|
Regex | GET .*servicedesk/customershim/secure/thumbnail/\d+ |
Example |
|
Action | Download or preview a file from the Customer Portal |
---|---|
Regex | GET .*servicedesk/customershim/secure/attachment/\d+ |
Example |
|
Field configuration admin actions
Action | Field configuration created |
---|---|
Regex | POST .*/secure/admin/AddFieldConfiguration.jspa |
Example |
|
Action | Field configuration deleted |
---|---|
Regex | POST .*/secure/admin/DeleteFieldLayout.jspa |
Example |
|
Action | Field configuration edited |
---|---|
Regex | POST .*/secure/admin/EditFieldLayout.jspa |
Example |
|
Action | Hide/show field from the field configuration page |
---|---|
Regex | GET .*/secure/admin/EditFieldLayoutHide.jspa |
Example |
|
Action | Hide/show field from the field configuration page for the Default Field Configuration |
---|---|
Regex | GET .*/secure/admin/IssueFieldHide.jspa |
Example |
|
Action | Make a field required/optional from the field configuration page |
---|---|
Regex | GET .*/secure/admin/EditFieldLayoutRequire.jspa |
Example |
|
Action | Make a field required/optional from the field configuration page for the Default Field Configuration |
---|---|
Regex | GET .*/secure/admin/IssueFieldRequire.jspa |
Example | 127.0.0.1 781x844x1 admin [06/Feb/2024:13:01:21 -0300] "GET /j5130/secure/admin/IssueFieldRequire.jspa?atl_token=BUT0-72QR-AYBL-F35N_82e6cf61be78684993add94661429414a8d5a977_lin&require=0 HTTP/1.1" 302 - 58 "http://localhost:45130/j5130/secure/admin/ViewIssueFields.jspa" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:122.0) Gecko/20100101 Firefox/122.0" "1oh3ydh" |
Action | Edit a field from the field configuration page |
---|---|
Regex | POST .*/secure/admin/EditFieldLayoutItem.jspa |
Example |
|
Action | Edit a field from the field configuration page for the Default Field Configuration |
---|---|
Regex | POST .*/secure/admin/EditDefaultFieldLayoutItem.jspa |
Example |
|
Statuses configuration admin actions
Action | View statuses |
---|---|
Regex | GET /secure/admin/ViewStatuses.jspa |
Example |
|
Action | Create a new status from the admin page |
---|---|
Regex | POST /secure/admin/AddStatus.jspa |
Example |
|
Action | Edit an existing status from the admin page |
---|---|
Regex | POST /secure/admin/EditStatus.jspa |
Example |
|
Action | Remove an existing status from the admin page |
---|---|
Regex | POST /secure/admin/DeleteStatus.jspa |
Example |
|
Action | View statuses translation |
---|---|
Regex | GET /secure/admin/ViewTranslations!default.jspa?issueConstantType=status |
Example |
|
Action | Edit statuses translation (this may indicate other translations as the type is passed through the request body) |
---|---|
Regex | POST /secure/admin/ViewTranslations.jspa |
Example |
|
Action | Create a new status from the workflow designer |
---|---|
Regex | POST /rest/workflowDesigner/latest/workflows/statuses |
Example |
|
Action | Edit an existing status from the workflow designer |
---|---|
Regex | PUT /rest/workflowDesigner/latest/workflows/statuses |
Example |
|
Action | Remove an existing status from the workflow designer |
---|---|
Regex | DELETE /rest/workflowDesigner/latest/workflows/statuses |
Example |
|