Jira: Audit User Actions via Access Logs


Jira doesn't come pre-build with information on who performed an action from the frontend. So, how can we find out who has updated a custom field that has impacted a lot of projects?

This is where the access logs come in, and Jira has this in the backend; running forever in the Tomcat Container.

Jira 6.1 and above already has an Audit Log feature built into the environment. This blog post may not apply to these versions of Jira, unless you want to go deeper into the access logs. Read more all about the Audit Log here: Auditing in Jira applications

Cover photo by Samuel Zeller on Unsplash

Find Out the Page that was Actioned Upon

So, let's say someone has added default values to a custom field; and this has impacted a lot of projects utilising this field. A project manager wanted to know who did this so that he can educate that user on the impact of his/her action.

For this example, let's say the affected field is the On hold reason field. Let's grab the URL when we choose to configure the field:
From the URL, deduce a unique identifier that distinguishes this custom field from the rest. Notice the red-boxed area in the screenshot above. Since we are finding a specific custom field change, grab the customfield_id:


Grab the Information from the Access Logs

  1. We know the ID of the affected custom field, now let's find a list of users who has access this page before. Go to your $JIRA_INSTALL/logs directory and perform an ls -lah access*:

    ls -lah access*
    -rw-rw-r-- 1 ec2-user ec2-user 2.8M Nov  2 00:00 access_log.2014-11-01
    -rw-rw-r-- 1 ec2-user ec2-user 1.1M Nov  2 23:58 access_log.2014-11-02
    -rw-rw-r-- 1 ec2-user ec2-user  40M Nov  3 23:59 access_log.2014-11-03
    -rw-rw-r-- 1 ec2-user ec2-user  35M Nov  4 23:59 access_log.2014-11-04
    -rw-rw-r-- 1 ec2-user ec2-user  34M Nov  5 23:59 access_log.2014-11-05
    -rw-rw-r-- 1 ec2-user ec2-user  32M Nov  6 23:57 access_log.2014-11-06
    -rw-rw-r-- 1 ec2-user ec2-user  30M Nov  7 23:59 access_log.2014-11-07
    -rw-rw-r-- 1 ec2-user ec2-user 883K Nov  8 23:58 access_log.2014-11-08
    -rw-rw-r-- 1 ec2-user ec2-user 733K Nov  9 23:58 access_log.2014-11-09
    -rw-rw-r-- 1 ec2-user ec2-user  29M Nov 10 23:59 access_log.2014-11-10
    -rw-rw-r-- 1 ec2-user ec2-user  43M Nov 11 23:58 access_log.2014-11-11
    -rw-rw-r-- 1 ec2-user ec2-user  38M Nov 12 23:59 access_log.2014-11-12
    -rw-rw-r-- 1 ec2-user ec2-user  33M Nov 13 23:58 access_log.2014-11-13
    -rw-rw-r-- 1 ec2-user ec2-user  29M Nov 14 23:59 access_log.2014-11-14
    -rw-rw-r-- 1 ec2-user ec2-user 2.1M Nov 15 23:57 access_log.2014-11-15
    -rw-rw-r-- 1 ec2-user ec2-user 1.7M Nov 16 23:57 access_log.2014-11-16
    -rw-rw-r-- 1 ec2-user ec2-user  32M Nov 17 23:56 access_log.2014-11-17
    -rw-rw-r-- 1 ec2-user ec2-user  36M Nov 18 23:59 access_log.2014-11-18
    -rw-rw-r-- 1 ec2-user ec2-user  32M Nov 19 23:59 access_log.2014-11-19
    -rw-rw-r-- 1 ec2-user ec2-user  35M Nov 20 23:59 access_log.2014-11-20
    -rw-rw-r-- 1 ec2-user ec2-user  26M Nov 21 23:58 access_log.2014-11-21
    -rw-rw-r-- 1 ec2-user ec2-user 3.2M Nov 22 23:58 access_log.2014-11-22
    -rw-rw-r-- 1 ec2-user ec2-user 1.9M Nov 23 23:58 access_log.2014-11-23
    -rw-rw-r-- 1 ec2-user ec2-user  31M Nov 24 23:59 access_log.2014-11-24
    -rw-rw-r-- 1 ec2-user ec2-user  37M Nov 25 23:59 access_log.2014-11-25
    -rw-rw-r-- 1 ec2-user ec2-user  32M Nov 26 23:59 access_log.2014-11-26
    -rw-rw-r-- 1 ec2-user ec2-user  38M Nov 27 23:58 access_log.2014-11-27
    -rw-rw-r-- 1 ec2-user ec2-user  25M Nov 28 23:59 access_log.2014-11-28
    -rw-rw-r-- 1 ec2-user ec2-user 781K Nov 29 23:57 access_log.2014-11-29
    -rw-rw-r-- 1 ec2-user ec2-user 1.4M Nov 30 23:57 access_log.2014-11-30
    -rw-rw-r-- 1 ec2-user ec2-user  36M Dec  1 23:59 access_log.2014-12-01
    -rw-rw-r-- 1 ec2-user ec2-user  38M Dec  2 23:59 access_log.2014-12-02
    -rw-rw-r-- 1 ec2-user ec2-user  38M Dec  3 23:57 access_log.2014-12-03
    -rw-rw-r-- 1 ec2-user ec2-user  36M Dec  4 23:59 access_log.2014-12-04
    -rw-rw-r-- 1 ec2-user ec2-user  32M Dec  6 00:00 access_log.2014-12-05
    -rw-rw-r-- 1 ec2-user ec2-user 4.5M Dec  6 23:58 access_log.2014-12-06
    -rw-rw-r-- 1 ec2-user ec2-user 1.7M Dec  7 23:59 access_log.2014-12-07
    -rw-rw-r-- 1 ec2-user ec2-user  45M Dec  9 00:00 access_log.2014-12-08
    -rw-rw-r-- 1 ec2-user ec2-user  39M Dec 10 00:00 access_log.2014-12-09
    -rw-rw-r-- 1 ec2-user ec2-user  37M Dec 11 00:00 access_log.2014-12-10
    -rw-rw-r-- 1 ec2-user ec2-user  29M Dec 11 23:59 access_log.2014-12-11
    -rw-rw-r-- 1 ec2-user ec2-user  32M Dec 13 00:00 access_log.2014-12-12
    -rw-rw-r-- 1 ec2-user ec2-user 3.1M Dec 13 23:59 access_log.2014-12-13
    -rw-rw-r-- 1 ec2-user ec2-user 2.6M Dec 15 00:00 access_log.2014-12-14
    -rw-rw-r-- 1 ec2-user ec2-user  38M Dec 15 23:59 access_log.2014-12-15
    -rw-rw-r-- 1 ec2-user ec2-user  38M Dec 16 18:03 access_log.2014-12-16
  2. From the command above, we found a lot of access_log files. Let's grep the above files for instances of the custom field that we are more interested in:

    less access* | grep '&customFieldId=10323' 1340x3799190x1 tmahsun [14/Dec/2014:22:20:42 +1100] "GET /secure/admin/ManageConfigurationScheme!default.jspa?atl_token=B14E-GL73-6FKZ-OP3B%7C1969712ab02334ed26991c8ca7a02224b2252db9%7Clin&fieldConfigSchemeId=13913&customFieldId=10323&returnUrl=ConfigureCustomField%21default.jspa%3FcustomFieldId%3D10323 HTTP/1.1" 200 101259 485 "https://pinkie-jira.com.au/secure/admin/ConfigureCustomField!default.jspa?customFieldId=10323" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/7.0)" "flt8wy" 1340x3799191x1 - [14/Dec/2014:22:20:42 +1100] "GET /s/d41d8cd98f00b204e9800998ecf8427e/en_US135a92-1988229788/6262/55/ebda7fb1e8929bc87f332ce20a1ecfe0/_/download/contextbatch/js/atl.admin/batch.js?cache=false&isAdmin=true&supportedApplication=true HTTP/1.1" 200 6840 5 "https://pinkie-jira.com.au/secure/admin/ManageConfigurationScheme!default.jspa?atl_token=B14E-GL73-6FKZ-OP3B%7C1969712ab02334ed26991c8ca7a02224b2252db9%7Clin&fieldConfigSchemeId=13913&customFieldId=10323&returnUrl=ConfigureCustomField%21default.jspa%3FcustomFieldId%3D10323" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/7.0)" "flt8wy"
  3. We can assume that the user tmahsun has perform edits in the custom field's default value, but that might not be the case. You may encounter a lot of lines from the command above, and that may exceed the limit of the terminal's buffer; so we may miss out a lot of other potential users as well. Let's output the command above to a file instead to grab all the information for investigation:

    less access* | grep '&customFieldId=10323' > cf-access
  4. Now if we were to less the file cf-access file, we can narrow down the users who has accessed this page:

    less cf-access 1340x3799190x1 tmahsun [14/Dec/2014:22:20:42 +1100] "GET /secure/admin/ManageConfigurationScheme!default.jspa?atl_token=B14E-GL73-6FKZ-OP3B%7C1969712ab02334ed26991c8ca7a02224b2252db9%7Clin&fieldConfigSchemeId=13913&customFieldId=10323&returnUrl=ConfigureCustomField%21default.jspa%3FcustomFieldId%3D10323 HTTP/1.1" 200 101259 485 "https://pinkie-jira.com.au/secure/admin/ConfigureCustomField!default.jspa?customFieldId=10323" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/7.0)" "flt8wy"
    ... 813x3906269x1 sysadmin [16/Dec/2014:13:33:51 +1100] "GET /secure/admin/ConfigureCustomField!default.jspa?customFieldId=10323 HTTP/1.1" 200 47363 438 "https://pinkie-jira.com.au/secure/admin/EditCustomFieldDefaults!default.jspa?atl_token=B14E-GL73-6FKZ-OP3B%7C193d84aec30b4d9394e50b40923c29a944b7af5a%7Clin&fieldConfigSchemeId=13913&fieldConfigId=15413&customFieldId=10323&returnUrl=ConfigureCustomField%21default.jspa%3FcustomFieldId%3D10323" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" "pb0gye"
  5. Only with the cf-access file can we drill down who has updated the custom field's default value, and we can safely say that username tmahsun is the user we're after (only if we are the sysadmin user that updated the field based on the project manager's request).

Final Words

With the above method, we can deduce almost all users' activities within a Jira instance. The only steps you have to do is:

  1. Find the distinguishable identifier from the affected page's URL.
  2. grep the logs for this information.