Skip to content

Instantly share code, notes, and snippets.

@erikcw
Last active August 22, 2023 10:58
Show Gist options
  • Save erikcw/e999e1fb438dbbb91533 to your computer and use it in GitHub Desktop.
Save erikcw/e999e1fb438dbbb91533 to your computer and use it in GitHub Desktop.
Simple nginx lua script to add UUID to each request for end to end request tracking.
# Dependencies
# nginx_lua
# lua uuid module (luarocks install uuid)
http {
# this will be the request id
map $host $request_uuid {
default '';
}
log_format log_with_request_id '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'request_id: $request_uuid';
server {
# your server block here ...
access_log /var/log/nginx.log log_with_request_id;
set_by_lua $request_uuid '
if ngx.var.http_x_request_id == nil then
return uuid()
else
return ngx.var.http_x_request_id
end
';
}
}
@omasseau
Copy link

omasseau commented Nov 5, 2021

Beware that $request_id generated by nginx is not a real UUID (it is not the same format).

@mjpieters
Copy link

Beware that $request_id generated by nginx is not a real UUID (it is not the same format).

That should not make a difference. UUID4 has 122 random bits (the remaining 6 are used to record the UUID version and variant, at least for the variant that LUA produces). The dashes between the hex digits are a convention, not a requirement for UUIDs; they simply delimit the 16 bytes into a groups of lengths 4, 2, 2, 2 and 6. You can 'transform' a $random_id value into a UUID with simple text transformations (replace the 13th hex digit with 4, update the 17th hex digit (0, 4, C -> 8; 1, 5, D -> 9; 2, 6, E -> A; 3, 7, F -> B), insert the dashes).

If all you need is a unique identifier for a request, $random_id is going to be way faster, don't get too hung up on the difference.

@raiden-dev
Copy link

Beware that $request_id generated by nginx is not a real UUID (it is not the same format).

That should not make a difference. UUID4 has 122 random bits (the remaining 6 are used to record the UUID version and variant, at least for the variant that LUA produces). The dashes between the hex digits are a convention, not a requirement for UUIDs; they simply delimit the 16 bytes into a groups of lengths 4, 2, 2, 2 and 6. You can 'transform' a $random_id value into a UUID with simple text transformations (replace the 13th hex digit with 4, update the 17th hex digit (0, 4, C -> 8; 1, 5, D -> 9; 2, 6, E -> A; 3, 7, F -> B), insert the dashes).

If all you need is a unique identifier for a request, $random_id is going to be way faster, don't get too hung up on the difference.

Looks like it could be implemented just with plain nginx's if and set statements:

# Sets $uuid variable as UUIDv4 (variant 1) converted from $request_id

set $uuid_m 4;

if ($request_id ~ '^(?<uuid_g1>[0-9a-f]{8})(?<uuid_g2>[0-9a-f]{4})(?<uuid_g3>[0-9a-f]{3})(?<uuid_n>[0-9a-f]{1})(?<uuid_g4>[0-9a-f]{3})(?<uuid_g5>[0-9a-f]{12})') {
}

if ($uuid_n = 0) {
  set $uuid_n 8;
}

if ($uuid_n = 4) {
  set $uuid_n 8;
}

if ($uuid_n = c) {
  set $uuid_n 8;
}

if ($uuid_n = 1) {
  set $uuid_n 9;
}

if ($uuid_n = 5) {
  set $uuid_n 9;
}

if ($uuid_n = d) {
  set $uuid_n 9;
}

if ($uuid_n = 2) {
  set $uuid_n a;
}

if ($uuid_n = 6) {
  set $uuid_n a;
}

if ($uuid_n = e) {
  set $uuid_n a;
}

if ($uuid_n = 3) {
  set $uuid_n b;
}

if ($uuid_n = 7) {
  set $uuid_n b;
}

if ($uuid_n = f) {
  set $uuid_n b;
}

set $uuid $uuid_g1-$uuid_g2-$uuid_m$uuid_g3-$uuid_n$uuid_g4-$uuid_g5;

@rmn-lux
Copy link

rmn-lux commented Jul 26, 2023

map would be nice for previous answer

map $uuid_n $uuid_n {
    0   8;
    1   9;
    2   a;
    3   b;
    4   8;
    5   9;
    6   a;
    7   b;
    c   8;
    d   9;
    e   a;
    f   b;
}


@mjpieters
Copy link

mjpieters commented Aug 9, 2023

Looks like it could be implemented just with plain nginx's if and set statements:

Your regex doesn't replace hex digit 13, you shifted digit 13-31 to positions 14-32, dropping off the 32nd hex digit. Probably not a big deal if your random values are properly random.

You can use a single map to do all the work with 4 regexes (one for each group of digit 17 values):

# map $request_id, a 32 (lowercase) hex digit random value, to a valid UUID4 value, formatted in 8h-4h-4h-4h-12h format.
# replaces hex digit 13 with '4', and the upper two bits of hex digit 17 with binary '10'
map $request_id $request_uuid4 {
    # <8h><4h><ignored h><3h><h digit for 0b??00><3h><12h>
    "~^(?<uuid_g1>[0-9a-f]{8})(?<uuid_g2>[0-9a-f]{4})[0-9a-f](?<uuid_g3>[0-9a-f]{3})[048c](?<uuid_g4>[0-9a-f]{3})(?<uuid_g5>[0-9a-f]{12})$" "${uuid_g1}-${uuid_g2}-4${uuid_g3}-8${uuid_g4}-${uuid_g5}";
    # <8h><4h><ignored h><3h><h digit for 0b??01><3h><12h>
    "~^(?<uuid_g1>[0-9a-f]{8})(?<uuid_g2>[0-9a-f]{4})[0-9a-f](?<uuid_g3>[0-9a-f]{3})[159d](?<uuid_g4>[0-9a-f]{3})(?<uuid_g5>[0-9a-f]{12})$" "${uuid_g1}-${uuid_g2}-4${uuid_g3}-9${uuid_g4}-${uuid_g5}";
    # <8h><4h><ignored h><3h><h digit for 0b??10><3h><12h>
    "~^(?<uuid_g1>[0-9a-f]{8})(?<uuid_g2>[0-9a-f]{4})[0-9a-f](?<uuid_g3>[0-9a-f]{3})[26ae](?<uuid_g4>[0-9a-f]{3})(?<uuid_g5>[0-9a-f]{12})$" "${uuid_g1}-${uuid_g2}-4${uuid_g3}-a${uuid_g4}-${uuid_g5}";
    # <8h><4h><ignored h><3h><h digit for 0b??11><3h><12h>
    "~^(?<uuid_g1>[0-9a-f]{8})(?<uuid_g2>[0-9a-f]{4})[0-9a-f](?<uuid_g3>[0-9a-f]{3})[37bf](?<uuid_g4>[0-9a-f]{3})(?<uuid_g5>[0-9a-f]{12})$" "${uuid_g1}-${uuid_g2}-4${uuid_g3}-b${uuid_g4}-${uuid_g5}";
}

# use $request_uuid4 in your log directive, or in a addheader directive to send the value back in responses.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment