Class: Pvectl::Commands::Logs::Command

Inherits:
Object
  • Object
show all
Defined in:
lib/pvectl/commands/logs/command.rb,
sig/pvectl/commands/logs/command.rbs

Overview

Dispatcher for the pvectl logs <resource_type> <id> command.

Routes requests to appropriate log handlers:

  • vm/ct: task history via Handlers::TaskLogs
  • node: syslog via Handlers::Syslog (or journal with --journal)
  • task: log lines via Handlers::TaskDetail

Examples:

Basic usage

Commands::Logs::Command.execute("vm", "100", options, global_options)

Constant Summary collapse

VM_CT_TYPES =

VM/CT resource types that use TaskLogs handler.

%w[vm vms ct container containers cts].freeze
NODE_TYPES =

Node resource types.

%w[node nodes].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(resource_type, resource_id, options, global_options, handler: nil, journal_handler: nil, registry: Logs::ResourceRegistry) ⇒ Command

Creates a new Logs command instance.



131
132
133
134
135
136
137
138
139
140
141
# File 'lib/pvectl/commands/logs/command.rb', line 131

def initialize(resource_type, resource_id, options, global_options,
               handler: nil, journal_handler: nil,
               registry: Logs::ResourceRegistry)
  @resource_type = resource_type
  @resource_id = resource_id
  @options = options
  @global_options = global_options
  @handler = handler
  @journal_handler = journal_handler
  @registry = registry
end

Class Method Details

.execute(resource_type, resource_id, options, global_options) ⇒ Integer

Executes the logs command.



118
119
120
# File 'lib/pvectl/commands/logs/command.rb', line 118

def self.execute(resource_type, resource_id, options, global_options)
  new(resource_type, resource_id, options, global_options).execute
end

.register(cli) ⇒ void

This method returns an undefined value.

Registers the logs command with the CLI.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/pvectl/commands/logs/command.rb', line 27

def self.register(cli)
  cli.desc "Show logs for resources (task history, syslog, journal)"
  cli.long_desc "    Show logs and task history for cluster resources. The log source\n    depends on the resource type:\n\n      vm / container    Task history (start, stop, backup, migrate, etc.)\n      node              System log (syslog by default, --journal for systemd)\n      task              Detailed log output for a specific task UPID\n\n    EXAMPLES\n      Node syslog (last 50 entries):\n        $ pvectl logs node pve1\n\n      Node systemd journal:\n        $ pvectl logs node pve1 --journal\n\n      Task history for a VM:\n        $ pvectl logs vm 100\n\n      Search VM tasks across all nodes:\n        $ pvectl logs vm 100 --all-nodes\n\n      Filter by task type and date:\n        $ pvectl logs vm 100 --type vzdump --since 2026-01-01\n\n      Detailed log for a specific task:\n        $ pvectl logs task UPID:pve1:000ABC:...\n\n      Filter node syslog by service:\n        $ pvectl logs node pve1 --service pvedaemon\n\n      Increase entry limit:\n        $ pvectl logs node pve1 --limit 200\n\n    NOTES\n      Default limit is 50 entries. Task detail (UPID) defaults to 512 lines.\n\n      --all-nodes searches across every cluster node for VM/CT tasks.\n      This is useful when a VM has been migrated between nodes.\n\n      Timestamps for --since and --until accept YYYY-MM-DD format\n      or Unix epoch seconds.\n\n    SEE ALSO\n      pvectl help get tasks     List task history cluster-wide\n      pvectl help describe      Detailed resource information\n  HELP\n  cli.arg_name \"RESOURCE_TYPE ID\"\n  cli.command :logs do |c|\n    c.desc \"Maximum number of entries to show\"\n    c.default_value 50\n    c.flag [:limit], type: Integer, arg_name: \"N\"\n\n    c.desc \"Show entries since timestamp (YYYY-MM-DD or epoch)\"\n    c.flag [:since], arg_name: \"TIMESTAMP\"\n\n    c.desc \"Show entries until timestamp (YYYY-MM-DD or epoch)\"\n    c.flag [:until], arg_name: \"TIMESTAMP\"\n\n    c.desc \"Filter by task type (e.g., qmstart, qmstop, vzdump)\"\n    c.flag [:type], arg_name: \"TYPE\"\n\n    c.desc \"Filter by status (running, ok, error)\"\n    c.flag [:status], arg_name: \"STATUS\"\n\n    c.desc \"Filter by service name (syslog only)\"\n    c.flag [:service], arg_name: \"SERVICE\"\n\n    c.desc \"Use systemd journal instead of syslog (node only)\"\n    c.switch [:journal], negatable: false\n\n    c.desc \"Search across all cluster nodes (VM/CT only)\"\n    c.switch [:\"all-nodes\"], negatable: false\n\n    c.action do |global_options, options, args|\n      resource_type = args[0]\n      resource_id = args[1]\n      exit_code = execute(resource_type, resource_id, options, global_options)\n      exit exit_code if exit_code != 0\n    end\n  end\nend\n"

Instance Method Details

#determine_color_enabledBoolean

Determines if color output should be enabled.



266
267
268
269
270
271
# File 'lib/pvectl/commands/logs/command.rb', line 266

def determine_color_enabled
  explicit = @global_options[:color]
  return explicit unless explicit.nil?

  $stdout.tty?
end

#executeInteger

Executes the logs operation.



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/pvectl/commands/logs/command.rb', line 146

def execute
  return missing_resource_type_error if @resource_type.nil?
  return missing_resource_id_error if @resource_id.nil? || @resource_id.empty?

  handler = resolve_handler
  return unknown_resource_error unless handler

  models = fetch_data(handler)
  output = format_output(models, handler.presenter)
  puts output

  ExitCodes::SUCCESS
rescue ResourceNotFoundError => e
  $stderr.puts "Error: #{e.message}"
  ExitCodes::NOT_FOUND
rescue Pvectl::Config::ConfigNotFoundError,
       Pvectl::Config::InvalidConfigError,
       Pvectl::Config::ContextNotFoundError,
       Pvectl::Config::ClusterNotFoundError,
       Pvectl::Config::UserNotFoundError => e
  $stderr.puts "Error: #{e.message}"
  ExitCodes::CONFIG_ERROR
rescue Timeout::Error, Errno::ECONNREFUSED, SocketError => e
  $stderr.puts "Error: #{e.message}"
  ExitCodes::CONNECTION_ERROR
end

#fetch_data(handler) ⇒ Array<Object>

Fetches data from the handler with appropriate parameters.



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/pvectl/commands/logs/command.rb', line 192

def fetch_data(handler)
  if VM_CT_TYPES.include?(@resource_type)
    handler.list(
      vmid: @resource_id.to_i,
      resource_type: @resource_type,
      all_nodes: @options[:"all-nodes"] || false,
      limit: @options[:limit] || 50,
      since: @options[:since],
      until_time: @options[:until],
      type_filter: @options[:type],
      status_filter: @options[:status]
    )
  elsif NODE_TYPES.include?(@resource_type)
    handler.list(
      node: @resource_id,
      limit: @options[:limit] || 50,
      since: @options[:since],
      until_time: @options[:until],
      service: @options[:service]
    )
  elsif @resource_type == "task"
    handler.list(
      upid: @resource_id,
      start: 0,
      limit: @options[:limit] || 512
    )
  else
    handler.list
  end
end

#format_output(models, presenter) ⇒ String

Formats models for output using the appropriate formatter.



256
257
258
259
260
261
# File 'lib/pvectl/commands/logs/command.rb', line 256

def format_output(models, presenter)
  format = @global_options[:output] || "table"
  color_enabled = determine_color_enabled
  formatter = Formatters::Registry.for(format)
  formatter.format(models, presenter, color_enabled: color_enabled)
end

#missing_resource_id_errorInteger

Outputs error for missing resource ID argument.



236
237
238
239
240
# File 'lib/pvectl/commands/logs/command.rb', line 236

def missing_resource_id_error
  $stderr.puts "Error: resource ID is required"
  $stderr.puts "Usage: pvectl logs #{@resource_type} ID [options]"
  ExitCodes::USAGE_ERROR
end

#missing_resource_type_errorInteger

Outputs error for missing resource type argument.



226
227
228
229
230
231
# File 'lib/pvectl/commands/logs/command.rb', line 226

def missing_resource_type_error
  $stderr.puts "Error: resource type is required"
  $stderr.puts "Usage: pvectl logs RESOURCE_TYPE ID [options]"
  $stderr.puts "Available resources: vm, ct, node, task"
  ExitCodes::USAGE_ERROR
end

#resolve_handlerObject?

Resolves the handler based on resource type and flags.



178
179
180
181
182
183
184
185
186
# File 'lib/pvectl/commands/logs/command.rb', line 178

def resolve_handler
  return @handler if @handler

  if NODE_TYPES.include?(@resource_type) && @options[:journal]
    @journal_handler || Handlers::Journal.new
  else
    @registry.for(@resource_type)
  end
end

#unknown_resource_errorInteger

Outputs error for unknown resource type.



245
246
247
248
249
# File 'lib/pvectl/commands/logs/command.rb', line 245

def unknown_resource_error
  $stderr.puts "Unknown resource type: #{@resource_type}"
  $stderr.puts "Available resources: vm, ct, node, task"
  ExitCodes::USAGE_ERROR
end