1## This Source Code Form is subject to the terms of the Mozilla Public 2## License, v. 2.0. If a copy of the MPL was not distributed with this 3## file, You can obtain one at https://mozilla.org/MPL/2.0/. 4## 5## Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. 6 7defmodule RabbitMQ.CLI.Diagnostics.Commands.MemoryBreakdownCommand do 8 alias RabbitMQ.CLI.InformationUnit, as: IU 9 import RabbitMQ.CLI.Core.Memory 10 11 @behaviour RabbitMQ.CLI.CommandBehaviour 12 13 def switches(), do: [unit: :string, timeout: :integer] 14 def aliases(), do: [t: :timeout] 15 16 def merge_defaults(args, opts) do 17 {args, Map.merge(%{unit: "gb"}, opts)} 18 end 19 20 def validate(args, _) when length(args) > 0 do 21 {:validation_failure, :too_many_args} 22 end 23 24 def validate(_, %{unit: unit}) do 25 case IU.known_unit?(unit) do 26 true -> 27 :ok 28 29 false -> 30 {:validation_failure, "unit '#{unit}' is not supported. Please use one of: bytes, mb, gb"} 31 end 32 end 33 34 use RabbitMQ.CLI.Core.RequiresRabbitAppRunning 35 36 def run([], %{node: node_name, timeout: timeout}) do 37 :rabbit_misc.rpc_call(node_name, :rabbit_vm, :memory, [], timeout) 38 end 39 40 def output(result, %{formatter: "json"} = _opts) do 41 {:ok, compute_relative_values(result)} 42 end 43 44 def output(result, %{formatter: "csv"} = _opts) do 45 flattened = 46 compute_relative_values(result) 47 |> Enum.flat_map(fn {k, %{bytes: b, percentage: p}} -> 48 [{"#{k}.bytes", b}, {"#{k}.percentage", p}] 49 end) 50 |> Enum.sort_by(fn {key, _val} -> key end, &>=/2) 51 52 headers = Enum.map(flattened, fn {k, _v} -> k end) 53 values = Enum.map(flattened, fn {_k, v} -> v end) 54 55 {:stream, [headers, values]} 56 end 57 58 def output(result, _opts) do 59 {:ok, compute_relative_values(result)} 60 end 61 62 def help_section(), do: :observability_and_health_checks 63 64 def description(), do: "Provides a memory usage breakdown on the target node." 65 66 def usage, do: "memory_breakdown [--unit <unit>]" 67 68 def usage_additional() do 69 [ 70 ["--unit <bytes | mb | gb>", "byte multiple (bytes, megabytes, gigabytes) to use"], 71 ["--formatter <json | csv | erlang>", "alternative formatter to use, JSON, CSV or Erlang terms"] 72 ] 73 end 74 75 def banner([], %{node: node_name}) do 76 "Reporting memory breakdown on node #{node_name}..." 77 end 78 79 defmodule Formatter do 80 alias RabbitMQ.CLI.Formatters.FormatterHelpers 81 alias RabbitMQ.CLI.InformationUnit, as: IU 82 83 @behaviour RabbitMQ.CLI.FormatterBehaviour 84 85 def format_output(output, %{unit: unit}) do 86 Enum.reduce(output, "", fn {key, %{bytes: bytes, percentage: percentage}}, acc -> 87 u = String.downcase(unit) 88 acc <> "#{key}: #{IU.convert(bytes, u)} #{u} (#{percentage}%)\n" 89 end) 90 end 91 92 def format_stream(stream, options) do 93 Stream.map( 94 stream, 95 FormatterHelpers.without_errors_1(fn el -> 96 format_output(el, options) 97 end) 98 ) 99 end 100 end 101 102 def formatter(), do: Formatter 103end 104