Как отслеживать ход передачи и вывода файла ssh в файл журнала - PullRequest
5 голосов
/ 16 мая 2011

Я пишу сценарий bash для периодической передачи данных в удаленную систему. У меня есть локальная команда, которая генерирует поток, и удаленная команда, которая его использует, поэтому я делаю что-то вроде этого:

generate_data | ssh remoteserver.example.com consume_data

(Там, где у меня настроены ssh-ключи, так что я могу делать это не в интерактивном режиме.) Это отлично работает. Однако, поскольку это будет автоматизированный процесс (работающий как задание cron), и иногда он может передавать большие объемы данных с ограниченной пропускной способностью, я хотел бы иметь возможность размещать периодические обновления прогресса в моем файле журнала. Я думал использовать для этого pv (просмотрщик каналов), и это лучшее, что я мог придумать:

generate_data | pv -fb | ssh remoteserver.example.com consume_data

Опять же, это работает ... , но pv действительно был написан с учетом вывода терминала, поэтому я в конечном итоге запутался в журнале, который выглядит как

2.06MB^M2.19MB^M2.37MB^M 2.5MB^M2.62MB^M2.87MB^M3MB^M3.12MB^M3.37MB

Я бы предпочел сообщения в журнале по строкам

<timestamp> 2.04MB transferred...
<timestamp> 3.08MB transferred...

Если у кого-нибудь есть какие-нибудь умные идеи о том, как это сделать, либо с аргументами, отличными от pv, либо с помощью другого механизма, я был бы признателен.

РЕДАКТИРОВАТЬ: Спасибо за ответы до сих пор. Конечно, есть много возможных решений домашнего приготовления; Я надеялся найти что-то, что будет работать "из коробки". (Не то чтобы я исключил домашнее варенье; в конце концов, это может быть самой простой вещью. Поскольку pv уже делает 98% того, что мне нужно, я бы предпочел не изобретать это заново.)

PostScript: Вот строка, которую я в конечном итоге использовал, в надежде, что в какой-то момент это может кому-то помочь.

{ generate_data | pv -fbt -i 60 2>&3 | ssh remoteserver consume_data } 3>&1 | awk -vRS='\r' '{print $1 " transferred in " $2; fflush();}' >> logfile

Ответы [ 5 ]

5 голосов
/ 17 мая 2011

Если вы хотите придерживаться pv, вы можете немного постобработать его вывод. Как минимум, превратить CR в LF.

{ generate_data | pv -bft 2>&3 | consume_data >/dev/null; } 3>&1 | tr '\015' '\012'

Используйте awk для более сложной обработки.

{ generate_data | pv -bft 2>&3 | consume_data >/dev/null; } 3>&1 |
awk -vRS='\r' '{print $2, $1 " transferred"}'

Однако имейте в виду, что стандартные утилиты обработки текста сбрасывают свои выходные данные только в конце каждой строки, если они печатают в терминал. Так что, если вы передадите pv другой утилите, чей вывод идет в канал или файл, будет существенная задержка из-за буферизации. Если у вас есть GNU awk или какая-либо другая реализация, которая имеет функцию fflush (это распространено, но не стандартно), заставьте ее сбрасывать вывод в каждой строке:

{ generate_data | pv -bft 2>&3 | consume_data >/dev/null; } 3>&1 |
awk -vRS='\r' '{print $2, $1 " transferred"; fflush()}'
2 голосов
/ 16 мая 2011

Вот небольшой рубиновый скрипт, который, я считаю, делает то, что вы хотите. Из-за издержек ruby ​​я получаю только около 1 МБ в секунду, копируя файл в локальную файловую систему, но вы упомянули, что каналы будут иметь ограниченную пропускную способность, так что это может быть нормально. Я вытащил функцию number_to_human_size из рельсов (actionview).

#!/usr/bin/ruby                                                                                                                           
require 'rubygems'
require 'active_support'

# File vendor/rails/actionpack/lib/action_view/helpers/number_helper.rb, line 87                                                          
def number_to_human_size(size)
  case
    when size < 1.kilobyte: '%d Bytes' % size
    when size < 1.megabyte: '%.1f KB'  % (size / 1.0.kilobyte)
    when size < 1.gigabyte: '%.1f MB'  % (size / 1.0.megabyte)
    when size < 1.terabyte: '%.1f GB'  % (size / 1.0.gigabyte)
    else                    '%.1f TB'  % (size / 1.0.terabyte)
  end.sub('.0', '')
rescue
  nil
end

UPDATE_FREQ = 2
count = 0
time1 = Time.now

while (!STDIN.eof?)
  b = STDIN.getc
  count += 1
  print b.chr
  time2 = Time.now
  if time2 - time1 > UPDATE_FREQ
    time1 = time2
    STDERR.puts "#{time2} #{number_to_human_size(count)} transferred..."
  end
end
1 голос
/ 18 мая 2011

Исходный код на http://code.google.com/p/pipeviewer/source/checkout, поэтому вы можете редактировать C и использовать PV!

EDIT: Да, получая исходный код, затем редактируйте строку 578 файла display.c, где он имеет следующий код:

    display = pv__format(&state, esec, sl, tot);
if (display == NULL)
    return;

if (opts->numeric) {
    write(STDERR_FILENO, display, strlen(display)); /* RATS: ignore */
} else if (opts->cursor) {
    pv_crs_update(opts, display);
} else {
    write(STDERR_FILENO, display, strlen(display)); /* RATS: ignore */
    write(STDERR_FILENO, "\r", 1);
}

Вы можете изменить "\ r" на "\ n" и перекомпилировать. Это может дать вам более полезный вывод, каждый раз выводя его на новую строку. И вы можете попробовать переформатировать всю эту строку вывода, если хотите.

1 голос
/ 17 мая 2011

Вы можете взглянуть на панель: http://clpbar.sourceforge.net/

Панель - это простой инструмент для копирования потока данных и печати для пользователя на stderr, показывающий (а) количествопереданные данные, (b) пропускная способность передачи данных и (c) время передачи или, если известен общий размер потока данных, приблизительное оставшееся время, какой процент передачи данных завершен, иИндикатор выполнения.

Индикатор был изначально написан для оценки количества времени, необходимого для передачи больших объемов данных (много-много гигабайт) по сети.(Обычно в трубе SSH / tar.)

0 голосов
/ 16 мая 2011

может быть небольшая Perl-программа, которая копирует STDIN в STDOUT и печатает его прогресс в STDERR?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...