Skip to content

Commit

Permalink
Show partition replica usage and limit in kafka:info (#168)
Browse files Browse the repository at this point in the history
* Show partition replica usage and limit in kafka:info

* Add pixelbar dep

* Add utilization bars to kafka:info

* Use the proper multiplication sign

* Make a simpler utilization bar

This drops pixelBar in favor of a builtin utilizationBar that does not use awesome unicode to fill partial blocks, because this leads to font issues.

* floor() not round() for utilizationBar
  • Loading branch information
msakrejda authored and idan committed Jul 11, 2017
1 parent ba2d4b3 commit 73078b4
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 30 deletions.
19 changes: 14 additions & 5 deletions commands/info.js
Expand Up @@ -3,6 +3,7 @@
const co = require('co')
const cli = require('heroku-cli-util')
const humanize = require('humanize-plus')
const utilizationBar = require('../lib/utilizationBar')

function configVarsFromName (attachments, name) {
return attachments
Expand All @@ -27,12 +28,13 @@ function formatInfo (info) {
lines.push({ name: 'Robot TTL', values: [cluster.robot.robot_ttl] })
}

let limits = cluster.limits
// we hide __consumer_offsets in topic listing; don't count it
const topicCount = cluster.topics.filter((topic) => topic !== '__consumer_offsets').length
if (cluster.limits && cluster.limits.max_topics) {
if (limits.max_topics) {
lines.push({
name: 'Topics',
values: [`${topicCount} / ${cluster.limits.max_topics} topics, see heroku kafka:topics`]
values: [`${utilizationBar(topicCount, limits.max_topics)} ${topicCount} / ${limits.max_topics} topics, see heroku kafka:topics`]
})
} else {
lines.push({
Expand All @@ -45,6 +47,13 @@ function formatInfo (info) {
lines.push({ name: 'Prefix', values: [cluster.topic_prefix] })
}

if (limits.max_partition_replica_count) {
lines.push({
name: 'Partitions',
values: [ `${utilizationBar(cluster.partition_replica_count, limits.max_partition_replica_count)} ${cluster.partition_replica_count} / ${limits.max_partition_replica_count} partition ${humanize.pluralize(cluster.partition_replica_count, 'replica')} (partitions × replication factor)` ]
})
}

lines.push({
name: 'Messages',
values: [`${humanize.intComma(cluster.messages_in_per_sec)} ${humanize.pluralize(cluster.messages_in_per_sec, 'message')}/s`]
Expand All @@ -55,13 +64,13 @@ function formatInfo (info) {
values: [`${humanize.fileSize(cluster.bytes_in_per_sec)}/s in / ${humanize.fileSize(cluster.bytes_out_per_sec)}/s out`]
})

if (cluster.data_size !== undefined && cluster.limits.data_size.limit_bytes !== undefined) {
if (cluster.data_size !== undefined && limits.data_size.limit_bytes !== undefined) {
let size = cluster.data_size
let limit = cluster.limits.data_size.limit_bytes
let limit = limits.data_size.limit_bytes
let percentage = ((size / limit) * 100.0).toFixed(2)
lines.push({
name: 'Data Size',
values: [`${humanize.fileSize(size)} / ${humanize.fileSize(limit)} (${percentage}%)`]
values: [`${utilizationBar(size, limit)} ${humanize.fileSize(size)} / ${humanize.fileSize(limit)} (${percentage}%)`]
})
}

Expand Down
14 changes: 14 additions & 0 deletions lib/utilizationBar.js
@@ -0,0 +1,14 @@
'use strict'

const chalk = require('chalk')

module.exports = function (current, total, width = 10) {
let percentage = current / total
if (percentage > 1) percentage = 1
if (percentage < 0) percentage = 0
const filled = Math.floor(percentage * width)
const empty = width - filled
let output = chalk.blue('█'.repeat(filled))
output += '·'.repeat(empty)
return `[${output}]`
}
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -7,6 +7,7 @@
"url": "https://github.com/heroku/heroku-kafka-jsplugin/issues"
},
"dependencies": {
"chalk": "^2.0.1",
"co": "4.6.0",
"co-wait": "0.0.0",
"debug": "2.6.8",
Expand Down
56 changes: 31 additions & 25 deletions test/commands/info_test.js
Expand Up @@ -75,6 +75,8 @@ describe('kafka:info', () => {
state: { message: 'available' },
robot: { is_robot: false },
topics: ['__consumer_offsets', 'messages'],
limits: {},
partition_replica_count: 132,
messages_in_per_sec: 0,
bytes_in_per_sec: 0,
bytes_out_per_sec: 0,
Expand All @@ -86,7 +88,8 @@ describe('kafka:info', () => {
state: { message: 'available' },
robot: { is_robot: false },
topics: ['__consumer_offsets', 'messages'],
limits: {max_topics: 10},
limits: {max_topics: 10, max_partition_replica_count: 32},
partition_replica_count: 12,
messages_in_per_sec: 0,
bytes_in_per_sec: 0,
bytes_out_per_sec: 0,
Expand Down Expand Up @@ -115,14 +118,15 @@ Traffic: 0 bytes/s in / 0 bytes/s out
Add-on: kafka-1
=== HEROKU_KAFKA_PURPLE_URL
Plan: heroku-kafka:beta-3
Status: available
Version: 0.10.0.0
Created: 2016-11-14T14:26:20.245+00:00
Topics: 1 / 10 topics, see heroku kafka:topics
Messages: 0 messages/s
Traffic: 0 bytes/s in / 0 bytes/s out
Add-on: kafka-2
Plan: heroku-kafka:beta-3
Status: available
Version: 0.10.0.0
Created: 2016-11-14T14:26:20.245+00:00
Topics: [█·········] 1 / 10 topics, see heroku kafka:topics
Partitions: [███·······] 12 / 32 partition replicas (partitions × replication factor)
Messages: 0 messages/s
Traffic: 0 bytes/s in / 0 bytes/s out
Add-on: kafka-2
`))
})
Expand All @@ -138,14 +142,15 @@ Add-on: kafka-2
return cmd.run({app: 'myapp', args: {CLUSTER: 'kafka-2'}})
.then(() => expect(cli.stderr).to.be.empty)
.then(() => expect(cli.stdout).to.equal(`=== HEROKU_KAFKA_PURPLE_URL
Plan: heroku-kafka:beta-3
Status: available
Version: 0.10.0.0
Created: 2016-11-14T14:26:20.245+00:00
Topics: 1 / 10 topics, see heroku kafka:topics
Messages: 0 messages/s
Traffic: 0 bytes/s in / 0 bytes/s out
Add-on: kafka-2
Plan: heroku-kafka:beta-3
Status: available
Version: 0.10.0.0
Created: 2016-11-14T14:26:20.245+00:00
Topics: [█·········] 1 / 10 topics, see heroku kafka:topics
Partitions: [███·······] 12 / 32 partition replicas (partitions × replication factor)
Messages: 0 messages/s
Traffic: 0 bytes/s in / 0 bytes/s out
Add-on: kafka-2
`))
})
Expand All @@ -160,14 +165,15 @@ Add-on: kafka-2

return cmd.run({app: 'myapp', args: {}})
.then(() => expect(cli.stdout).to.equal(`=== HEROKU_KAFKA_PURPLE_URL
Plan: heroku-kafka:beta-3
Status: available
Version: 0.10.0.0
Created: 2016-11-14T14:26:20.245+00:00
Topics: 1 / 10 topics, see heroku kafka:topics
Messages: 0 messages/s
Traffic: 0 bytes/s in / 0 bytes/s out
Add-on: kafka-2
Plan: heroku-kafka:beta-3
Status: available
Version: 0.10.0.0
Created: 2016-11-14T14:26:20.245+00:00
Topics: [█·········] 1 / 10 topics, see heroku kafka:topics
Partitions: [███·······] 12 / 32 partition replicas (partitions × replication factor)
Messages: 0 messages/s
Traffic: 0 bytes/s in / 0 bytes/s out
Add-on: kafka-2
`))
.then(() => expect(cli.stderr).to.equal(` ▸ kafka-1 is not yet provisioned.
Expand Down
29 changes: 29 additions & 0 deletions test/lib/utilizationBar_test.js
@@ -0,0 +1,29 @@
'use strict'

const expect = require('chai').expect
const mocha = require('mocha')
const describe = mocha.describe
const it = mocha.it

const utilizationBar = require('../../lib/utilizationBar')

describe('utilizationBar', function () {
const cases = [
[0, 100, '[··········]', '[···············]'],
[100, 100, '[\u001b[34m██████████\u001b[39m]', '[\u001b[34m███████████████\u001b[39m]'],
[99, 100, '[\u001b[34m█████████\u001b[39m·]', '[\u001b[34m██████████████\u001b[39m·]'],
[50, 100, '[\u001b[34m█████\u001b[39m·····]', '[\u001b[34m███████\u001b[39m········]'],
[110, 100, '[\u001b[34m██████████\u001b[39m]', '[\u001b[34m███████████████\u001b[39m]'],
[-50, 100, '[··········]', '[···············]']
]
cases.forEach(function (testcase) {
const current = testcase[0]
const total = testcase[1]
const expected10 = testcase[2]
const expected15 = testcase[3]
it(`Renders a ${current}/${total} bar correctly`, function () {
expect(utilizationBar(current, total)).to.equal(expected10)
expect(utilizationBar(current, total, 15)).to.equal(expected15)
})
})
})
34 changes: 34 additions & 0 deletions yarn.lock
Expand Up @@ -61,6 +61,12 @@ ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"

ansi-styles@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.1.0.tgz#09c202d5c917ec23188caa5c9cb9179cd9547750"
dependencies:
color-convert "^1.0.0"

ansicolors@~0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef"
Expand Down Expand Up @@ -400,6 +406,14 @@ chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"

chalk@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.0.1.tgz#dbec49436d2ae15f536114e76d14656cdbc0f44d"
dependencies:
ansi-styles "^3.1.0"
escape-string-regexp "^1.0.5"
supports-color "^4.0.0"

circular-json@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d"
Expand Down Expand Up @@ -463,6 +477,16 @@ code-point-at@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"

color-convert@^1.0.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
dependencies:
color-name "^1.1.1"

color-name@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.2.tgz#5c8ab72b64bd2215d617ae9559ebb148475cf98d"

combined-stream@^1.0.5, combined-stream@~1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
Expand Down Expand Up @@ -1202,6 +1226,10 @@ has-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"

has-flag@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"

has-unicode@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
Expand Down Expand Up @@ -2904,6 +2932,12 @@ supports-color@^3.1.2:
dependencies:
has-flag "^1.0.0"

supports-color@^4.0.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.2.0.tgz#ad986dc7eb2315d009b4d77c8169c2231a684037"
dependencies:
has-flag "^2.0.0"

symbol-observable@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d"
Expand Down

0 comments on commit 73078b4

Please sign in to comment.