Skip to content

Conversation

p0rtale
Copy link
Contributor

@p0rtale p0rtale commented Jun 25, 2025

This change adds support for predefined label keys in counter and gauge metric constructors, optimizing label processing.

Changes:

  • Add optional label_keys table to counter() and gauge() initialization
  • Replace dynamic label sorting with direct key generation when label_keys are provided, eliminating unnecessary processing overhead

Dynamic labels still supported when label_keys is omitted.

Closes TNTP-3453

@p0rtale
Copy link
Contributor Author

p0rtale commented Jun 25, 2025

variable labels: 85.6 s
fixed labels: 36.5 s

Bench script
local metrics = require('metrics')
local clock = require('clock')
local log = require('log')

local GAUGES_COUNT = 75
local KEYS_COUNT = 10000
local OPS_COUNT = 50000000

local label_keys = {
    "service", "version", "env", "region", "status", "deployment"
}

local label_values = {
    service = { "auth", "cart", "payment", "storage", "analytics", "notify", "gateway" },
    version = { "v1.0", "v1.1", "v1.2", "v2.0", "v2.1", "v2.2", "v3.0-beta" },
    env = { "prod", "stage", "dev", "test", "canary" },
    region = { "eu-west", "us-east", "us-west", "asia-south", "asia-east" },
    status = { "active", "inactive", "draining", "booting" },
    deployment = { "blue", "green", "red", "canary" }
}

local function generate_random_labels()
    local labels = {}
    for _, key in ipairs(label_keys) do
        local values = label_values[key]
        labels[key] = values[math.random(1, #values)]
    end
    return labels
end

local label_combinations = {}
for _ = 1, KEYS_COUNT do
    table.insert(label_combinations, generate_random_labels())
end

local var_gauges = {}
local fixed_gauges = {}
for i = 1, GAUGES_COUNT do
    var_gauges[i] = metrics.gauge('var_gauge_' .. i, 'Description for gauge ' .. i)
    fixed_gauges[i] = metrics.gauge('fixed_gauge_' .. i, 'Description for gauge ' .. i, {}, label_keys)
end

local function run_bench(gauges)
    local start_time = clock.monotonic()

    for _ = 1, OPS_COUNT do
        local gauge_idx = math.random(1, #gauges)
        local label_idx = math.random(1, #label_combinations)
        local value = math.random(1, 1000)

        gauges[gauge_idx]:set(value, label_combinations[label_idx])
    end

    return clock.monotonic() - start_time
end

local t1 = run_bench(var_gauges)
local t2 = run_bench(fixed_gauges)
local t3 = run_bench(var_gauges)
local t4 = run_bench(fixed_gauges)

log.info("variable labels: %.10f s", (t1 + t3) / 2)
log.info("fixed labels: %.10f s", (t2 + t4) / 2)

Copy link
Member

@DifferentialOrange DifferentialOrange left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the motivation? Is it the optimization or more assertive API for metrics users? If it's the optimization, I think the solution can be expanded to remove redundant table allocation (parts = {}) or even table.concat. As far as I remember, they also take a lot of work.

We shouldn't forget to

  1. add a CHANGELOG entry,
  2. update the API documentation (like here).

Comment on lines 48 to 52
if type(label_pairs) ~= 'table' then
return ""
end

if label_keys ~= nil then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it be

Suggested change
if type(label_pairs) ~= 'table' then
return ""
end
if label_keys ~= nil then
if (label_keys == nil) and (type(label_pairs) ~= 'table') then
return ""
end
if label_keys ~= nil then

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If label_keys is not nil and label_pairs is invalid, we won't be able to make the key

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you're fine with ignoring invalid label_pairs, including nil?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see what you mean now

Copy link
Member

@DifferentialOrange DifferentialOrange left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have any more question to this implementation. There is also a field for improvement. For example, one can create parts table and compute keys length only once per collector. Maybe table.concat can be removed at all in spite of some pre-built format string. Is there actually a performance increase? And how much is it?

@oleg-jukovec oleg-jukovec self-requested a review July 7, 2025 10:42
Copy link
Contributor

@oleg-jukovec oleg-jukovec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, squash commits into a single one well-described commit.

@oleg-jukovec oleg-jukovec merged commit 1f81509 into tarantool:master Jul 7, 2025
patapenka-alexey added a commit to tarantool/tarantool that referenced this pull request Oct 22, 2025
Bump metric package submodule to 1.6.1. Commits from PR[1-8] add
and remove metrics to Tarantool.

1. tarantool/metrics#508
2. tarantool/metrics#516
3. tarantool/metrics#519
4. tarantool/metrics#521
5. tarantool/metrics#524
6. tarantool/metrics#525
7. tarantool/metrics#527
8. tarantool/metrics#529

Closes #11950

@TarantoolBot document
Title: Bump metrics module to 1.6.1

`'tnt_memory'`, `'tnt_memory_virt'`, `'schema_needs_upgrade'` are new
metrics, introduced in metrics 1.6.0, and enabled by default.

`'tnt_cartridge_config_checksum'` is new metric, introduced in
metrics 1.5.0.

New optional ``label_keys`` parameter for ``counter()`` and ``gauge()``
metrics are presented in metrics 1.4.0.
patapenka-alexey added a commit to tarantool/tarantool that referenced this pull request Oct 22, 2025
Bump metric package submodule to 1.6.1. Commits from PR[1-7] add
and remove metrics to Tarantool.

1. tarantool/metrics#508
2. tarantool/metrics#516
3. tarantool/metrics#519
4. tarantool/metrics#521
5. tarantool/metrics#524
6. tarantool/metrics#527
7. tarantool/metrics#529

Closes #11950

@TarantoolBot document
Title: Bump metrics module to 1.6.1

`'tnt_memory'`, `'tnt_memory_virt'`, `'schema_needs_upgrade'` are new
metrics, introduced in metrics 1.6.0, and enabled by default.

`'tnt_cartridge_config_checksum'` is new metric, introduced in
metrics 1.5.0.

New optional ``label_keys`` parameter for ``counter()`` and ``gauge()``
metrics are presented in metrics 1.4.0.
patapenka-alexey added a commit to tarantool/tarantool that referenced this pull request Oct 22, 2025
Bump metric package submodule to 1.6.1. Commits from PR[1-7] add
new metrics to Tarantool.

1. tarantool/metrics#508
2. tarantool/metrics#516
3. tarantool/metrics#519
4. tarantool/metrics#521
5. tarantool/metrics#524
6. tarantool/metrics#527
7. tarantool/metrics#529

Closes #11950

@TarantoolBot document
Title: Bump metrics module to 1.6.1

`'tnt_memory'`, `'tnt_memory_virt'`, `'schema_needs_upgrade'` are new
metrics, introduced in metrics 1.6.0, and enabled by default.

`'tnt_cartridge_config_checksum'` is new metric, introduced in
metrics 1.5.0.

New optional ``label_keys`` parameter for ``counter()`` and ``gauge()``
metrics are presented in metrics 1.4.0.
patapenka-alexey added a commit to tarantool/tarantool that referenced this pull request Oct 22, 2025
Bump metric package submodule to 1.6.1. Commits from PR[1-7] add
new metrics to Tarantool.

1. tarantool/metrics#508
2. tarantool/metrics#516
3. tarantool/metrics#519
4. tarantool/metrics#521
5. tarantool/metrics#524
6. tarantool/metrics#527
7. tarantool/metrics#529

Closes #11950

@TarantoolBot document
Title: Bump metrics module to 1.6.1

`'tnt_memory'`, `'tnt_memory_virt'`, `'schema_needs_upgrade'` are new
metrics, introduced in metrics 1.6.0, and enabled by default.

`'tnt_cartridge_config_checksum'` is new metric, introduced in
metrics 1.5.0.

New optional ``label_keys`` parameter for ``counter()`` and ``gauge()``
metrics are presented in metrics 1.4.0.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants