更改 top 中 Ruby 进程的名称

22

我想要更改在Linux/Unix top命令中显示的Ruby进程名称。我尝试了

$0='miname'

这个方法只适用于使用 ps 命令,而在 top 命令中该进程一直显示为 "ruby"。

7个回答

17

戴夫·托马斯在他的博客文章中提到了如何在Rails中实现进程名称修改。关于进程名称更改的代码,与Rails本身无关。他使用了$0='name'方法。当我按照他的步骤进行操作后,在pstop命令中都看到了进程名称的更改。

在此帖子中,他建议使用键盘命令c,如果您的top版本默认不显示命令的简短版本。


1
我已尝试了C键盘命令并且在Linux机器上运作良好。Mac OS X的top命令似乎没有相应的选项。 - muesan
1
链接已失效 :( 你能否展示一些代码? - Automatico
2
网络档案馆拯救生命:https://web.archive.org/web/20130415202502/http://pragdave.blogs.pragprog.com/pragdave/2008/11/trivial-request-logging-for-rails.html - armoucar
这就是为什么你不应该只给一个链接的原因 :) - Yasen

10

我在OSX上使用Ruby 2.2,而Process.setproctitle确实会更改我在ps -ef中看到的内容,而$0 =“something”(或$PROGRAM_NAME =“something”)却不会。 - Nathan Long
1
我正在使用Linux,这个答案与$0="My new title"相同,它只是改变了ps输出,不能与pgrep或pkill一起使用。 - zw963

9
我认为Ruby没有内置设施(setproctitle(3))。你应该尝试查看ruby-ffi并创建与setproctitle(3)的接口。

编辑:我知道你已经得到了答案,但是我想向你展示一些使用ffi的代码:

require "ffi"
#
module LibC
  extend FFI::Library

  attach_function :setproctitle, [:string, :varargs], :void
end

LibC.setproctitle("Ruby: executing %s", :string, $0)

因为在OS X上不存在setproctitle(3),所以无法工作,但在FreeBSD上可以。


1
虽然这是一个很好的FFI示例,但你使用的函数根本不具备可移植性。它似乎只适用于FreeBSD和其他BSD版本,而不支持Linux(glibc)、OS X或Windows系统。 - dequis

2

我曾经遇到过类似的问题,参考了Dave Thomas的文章并稍微改进了一下技术方法,将其放在一个Rack中间件中,而不是使用before/after模式。

将以下代码放在lib/rack/set_process_title.rb文件中:

# Set the process title to the URI being processed 
#- useful for debugging slow requests or those that get stuck
class Rack::SetProcessTitle
  def initialize(app)
    @app = app
  end
  def call(env)
    $0 = env['REQUEST_URI'][0..80]

    @status, @headers, @response = @app.call(env)

    $0 = env['REQUEST_URI'][0..80] + '*'

    [@status, @headers, @response]
  end
end

...并将其放置在config/environment.rb的末尾:

Rails.configuration.middleware.insert_after Rack::Lock, Rack::SetProcessTitle

博客文章中的更多内容:http://blog.actbluetech.com/2011/06/set-your-process-name-in-top-and-ps.html


2

使用 $0 = 'Foo' 方法可以实现目标 -- 但是在很多版本的 top 中,你需要通过 'c' 命令行模式来切换。我们在 rails 和 CentOS 中使用这种方法非常有效。


那么,你怎么做到这一点呢? - Automatico

2

我知道Keltia已经发布了非常类似的内容,但Linux没有setproctitle(3)函数。自2.6.9版本以来,Linux已经在prctl()中实现了这个功能。我使用Fiddle / DL,因为它们默认包含在Ruby中。

require("fiddle")

def set_process_name_linux(name)
    Fiddle::Function.new(
        Fiddle::Handle["prctl".freeze], [
            Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP,
            Fiddle::TYPE_LONG, Fiddle::TYPE_LONG,
            Fiddle::TYPE_LONG
        ], Fiddle::TYPE_INT
    ).call(15, name, 0, 0, 0)
end

def set_process_name_unknown(name)
    warn("No implementation for this OS.".freeze)
end

def set_process_name(name)
    case RUBY_PLATFORM.split("-".freeze)[1]
    when "linux".freeze
        set_process_name_linux(name)
    else
        set_process_name_unknown(name)
    end
end

1
在Ruby 2.2.3上,DL已被弃用,需要更改一行代码。DL :: Handle需要更改为Fiddle :: Handle才能正常工作。此答案可以在Linux上完美运行,它不会更改ps输出,但可以与pgrep一起使用。 - zw963

0

根据@jessehz的回答,以下代码在我的Linux X86_64上完美运行。 已测试Ruby 1.9.3、2.0、2.1、2.2、2.3。

  1. 它将更改ps top命令的输出。
  2. 可以使用pkill、pgrep、killall进行杀死或信号处理。

完美!

def set_process_name_linux(name)
  handle = defined?(DL::Handle) ? DL::Handle : Fiddle::Handle

  Fiddle::Function.new(
    handle['prctl'.freeze], [
      Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP,
      Fiddle::TYPE_LONG, Fiddle::TYPE_LONG,
      Fiddle::TYPE_LONG
    ], Fiddle::TYPE_INT
  ).call(15, name, 0, 0, 0)
  $PROGRAM_NAME = name
end
set_process_name_linux('dummy')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接