cli_application 0.1.9 → 0.1.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/cli_application.rb +7 -0
- data/lib/cli_application/app.rb +30 -2
- data/lib/cli_application/config.rb +2 -0
- data/lib/cli_application/locales/ru.yml +20 -0
- data/lib/cli_application/log/README.md +57 -0
- data/lib/cli_application/log/base.rb +27 -0
- data/lib/cli_application/log/config.rb +71 -0
- data/lib/cli_application/log/database.rb +21 -0
- data/lib/cli_application/log/file.rb +96 -0
- data/lib/cli_application/log/none.rb +19 -0
- data/lib/cli_application/stat.rb +70 -46
- data/lib/cli_application/version.rb +1 -1
- data/test/examples/1/stat/app.yml +15 -27
- data/test/log/01_log_section_missing/app.rb +24 -0
- data/test/log/01_log_section_missing/cli_example.rb +14 -0
- data/test/log/02_log_section_type_wrong/app.rb +24 -0
- data/test/log/02_log_section_type_wrong/cli_example.rb +14 -0
- data/test/log/02_log_section_type_wrong/stat/app.yml +21 -0
- data/test/log/03_log_section_type_none_ok/app.rb +24 -0
- data/test/log/03_log_section_type_none_ok/cli_example.rb +14 -0
- data/test/log/03_log_section_type_none_ok/stat/app.yml +26 -0
- data/test/log/04_log_section_type_file_ok/app.rb +25 -0
- data/test/log/04_log_section_type_file_ok/cli_example.rb +14 -0
- data/test/log/04_log_section_type_file_ok/logs/app.log +11 -0
- data/test/log/04_log_section_type_file_ok/stat/app.yml +33 -0
- metadata +29 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97e161aaae872e64c8eb70ae91392d210c789564
|
4
|
+
data.tar.gz: c5d7d088bedf9edb2b02eaa0348d0d2da3a272cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55ae149543d5269befed662bb517dc4caf9137d45f9d0bb9afa345a7093fba129a8cdf9afb6134c499920fe90d92955afe990bf452eb399de8f5315e8b390ea6
|
7
|
+
data.tar.gz: bb55fb421ad8fc54f29db17678b788332151b7a37115c097be66063025b908e518318efab920ed87b363a8f969d87b37a57702972573f2c2df24e0cd8d38c204
|
data/lib/cli_application.rb
CHANGED
@@ -24,6 +24,13 @@ module CliApplication # :nodoc:
|
|
24
24
|
require 'cli_application/mail_lib/sendmail'
|
25
25
|
require 'cli_application/mail_lib/log'
|
26
26
|
|
27
|
+
# Функции записи логов в файл или в базу данных
|
28
|
+
require 'cli_application/log/base'
|
29
|
+
require 'cli_application/log/file'
|
30
|
+
require 'cli_application/log/database'
|
31
|
+
require 'cli_application/log/config'
|
32
|
+
require 'cli_application/log/none'
|
33
|
+
|
27
34
|
require 'cli_application/json_struct'
|
28
35
|
require 'cli_application/config'
|
29
36
|
require 'cli_application/databases'
|
data/lib/cli_application/app.rb
CHANGED
@@ -35,7 +35,13 @@ module CliApplication
|
|
35
35
|
# @param [String] classfolder директория, в которой расположен базовый класс проекта
|
36
36
|
# @param [Sym] lang язык работы приложения (реализовано не полностью)
|
37
37
|
def initialize(argv, appfolder, classfolder, lang = :ru)
|
38
|
+
# ru: Настраиваем локализацию приложения
|
39
|
+
# en: setup a localization
|
38
40
|
StTools.configure { |config| config.locale = lang }
|
41
|
+
I18n.load_path += Dir[File.join(__dir__, 'locales', '*.{rb,yml}')]
|
42
|
+
I18n.available_locales = [:ru]
|
43
|
+
I18n.default_locale = lang
|
44
|
+
I18n.backend.load_translations
|
39
45
|
|
40
46
|
@folders = Hash.new
|
41
47
|
@folders[:app] = appfolder
|
@@ -50,9 +56,23 @@ module CliApplication
|
|
50
56
|
|
51
57
|
@footer = nil
|
52
58
|
|
59
|
+
init_app_log
|
53
60
|
init_app
|
54
61
|
end
|
55
62
|
|
63
|
+
def init_app_log
|
64
|
+
log_config = ::CliApplication::Log::Config.new(@config)
|
65
|
+
case log_config.type
|
66
|
+
when :none
|
67
|
+
@cli_log = ::CliApplication::Log::None.new
|
68
|
+
when :file
|
69
|
+
@cli_log = ::CliApplication::Log::File.new(self, log_config, @folders[:class])
|
70
|
+
else
|
71
|
+
raise I18n.t('error.config.log_unknown', type: log_config.type.to_s.inspect)
|
72
|
+
end
|
73
|
+
@cli_log.save_app_start_information
|
74
|
+
end
|
75
|
+
|
56
76
|
#-------------------------------------------------------------
|
57
77
|
#
|
58
78
|
# Функции для использования внутри функции main
|
@@ -223,8 +243,16 @@ module CliApplication
|
|
223
243
|
|
224
244
|
# При вызове данного метода начнется выполнение кода приложения (будет осуществен вызов функции main)
|
225
245
|
def run
|
226
|
-
|
227
|
-
|
246
|
+
@cli_log.save_app_run_information
|
247
|
+
begin
|
248
|
+
self.exitcode = main || 255
|
249
|
+
rescue Exception => e
|
250
|
+
@cli_log.set_exception(e)
|
251
|
+
raise e
|
252
|
+
ensure
|
253
|
+
self.executed_at = (::Time.now - @started_at).to_f
|
254
|
+
@cli_log.save_app_finish_information
|
255
|
+
end
|
228
256
|
puts_footer
|
229
257
|
@cli_stat_record.save
|
230
258
|
self.exitcode
|
@@ -10,6 +10,7 @@
|
|
10
10
|
module CliApplication
|
11
11
|
class Config < OpenStruct
|
12
12
|
attr_reader :config
|
13
|
+
attr_reader :filename
|
13
14
|
|
14
15
|
# Конструктор. Вызывается при создании класса приложения. Данный класс доступен
|
15
16
|
# в главной функции приложения (main) через переменную config
|
@@ -21,6 +22,7 @@ module CliApplication
|
|
21
22
|
@folders = folders
|
22
23
|
@filenames = Array.new
|
23
24
|
@config_filename = File.join([folders[:class], 'config.yml'])
|
25
|
+
@filename = @config_filename
|
24
26
|
load_config(@config_filename)
|
25
27
|
end
|
26
28
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
ru:
|
2
|
+
error:
|
3
|
+
config:
|
4
|
+
log_section_missing: "В конфигурационном файле %{filename} отсутствует секция \"log\""
|
5
|
+
log_section_type_wrong: "Секция \"log\" конфигурационого файла %{filename} должна принимать одно из следующих значений: none, file, database (указано значение %{type})"
|
6
|
+
log_unknown: "Неизвестный тип логгирования: %{type}"
|
7
|
+
log_section_overwrite: "Необходимо переписать функцию \"%{func}\" в дочернем классе"
|
8
|
+
|
9
|
+
config:
|
10
|
+
log_section:
|
11
|
+
start_header: "-- Запуск приложения ---------------------------"
|
12
|
+
run_header: "-- Пользовательская секция ---------------------"
|
13
|
+
finish_header: "-- Завершение приложения -----------------------"
|
14
|
+
app_name: "Приложение: %{name}"
|
15
|
+
app_started_at: "Приложение запущено: %{time}"
|
16
|
+
app_executed_at: "Приложение завершено: %{time} (время выполнения: %{executed_at} сек.)"
|
17
|
+
app_exitcode: "Результат завершения: %{exitcode} (%{status})"
|
18
|
+
app_memory: "Использование памяти: %{value}"
|
19
|
+
app_script_name: "Имя скрипта: %{name}"
|
20
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# module CliApplication::Log
|
2
|
+
|
3
|
+
В ходе эксплуатации библиотеки мне пришлось столкнуться с некоторыми проблемами, которые не сразу были
|
4
|
+
диагностированы. Например, в ходе выполнения скрипта, через полгода, случайно выяснялось, что скрипт
|
5
|
+
последний месяц работал с ошибкой. Подобных ситуаций может быть две:
|
6
|
+
|
7
|
+
- Cкрипт был отлажен под девелоперским профилем, записаны логи, затем скрипт помещен в cron. После этого,
|
8
|
+
при запуске из под крона, возникала ошибка записи лога (из-под крона другие права), которая не выводилась
|
9
|
+
в консоль. Как следствие - под кроном скрипт не работет, а причина неизвестна.
|
10
|
+
- В ходе исполнения скрипта возникали не предусмотренные на этапе отладки исключительные ситуации, и скрипт
|
11
|
+
прекращал работать. Если не озаботиться выводом диагностических сообщений, например, в почту, то об этой
|
12
|
+
ситуации можно было долго не узнать.
|
13
|
+
|
14
|
+
Поэтому в CliApplication добавляются функции логгирования работы приложения. Практика показывет, что полные
|
15
|
+
логи никто не изучает (трудоемко), поэтому логгирование осуществляется только для последнего запуска скрипта.
|
16
|
+
|
17
|
+
При этом, функции логгирования делают следующее:
|
18
|
+
1. Уже на этапе девелопмента предупреждают о ситуации, если запись лог-файлов будет ограничена по причине прав.
|
19
|
+
Это дает гарантию того, что при запуске из под крона данные будут гарантированно записываться в файл.
|
20
|
+
2. Записывают информацию о старте приложения. Если есть блок старта приложения, и ничего больше - где-то
|
21
|
+
произошел "вылет" приложения.
|
22
|
+
3. Дает возможность записи пользовательских сообщений (например, для отладки или контроля исполнения)
|
23
|
+
4. Пишет финальную часть - время исполнения, результат, занятую память.
|
24
|
+
|
25
|
+
Помимо файла, запись также возможна в базу данных, что дает возможность удаленно мониторить исполнение
|
26
|
+
скриптов
|
27
|
+
|
28
|
+
## Настройка логгирования
|
29
|
+
|
30
|
+
Для настройки логгирования необходимо создать секцию cli/log в конфигурационном файле. Формат секции
|
31
|
+
определяется значением type. Например:
|
32
|
+
|
33
|
+
```yaml
|
34
|
+
cli:
|
35
|
+
log:
|
36
|
+
type: none
|
37
|
+
```
|
38
|
+
|
39
|
+
```yaml
|
40
|
+
cli:
|
41
|
+
log:
|
42
|
+
type: file
|
43
|
+
location: <folder>
|
44
|
+
```
|
45
|
+
|
46
|
+
```yaml
|
47
|
+
cli:
|
48
|
+
log:
|
49
|
+
type: database
|
50
|
+
database: <имя секции cli/database>
|
51
|
+
```
|
52
|
+
|
53
|
+
## Логгирование в файл
|
54
|
+
|
55
|
+
|
56
|
+
## Логгирование в базу данных
|
57
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module CliApplication
|
2
|
+
module Log
|
3
|
+
class Base
|
4
|
+
|
5
|
+
def log(message)
|
6
|
+
raise I18n.t('error.config.log_section_overwrite', func: 'log')
|
7
|
+
end
|
8
|
+
|
9
|
+
def save_app_start_information
|
10
|
+
raise I18n.t('error.config.log_section_overwrite', func: 'save_app_start_information')
|
11
|
+
end
|
12
|
+
|
13
|
+
def save_app_run_information
|
14
|
+
raise I18n.t('error.config.log_section_overwrite', func: 'save_app_run_information')
|
15
|
+
end
|
16
|
+
|
17
|
+
def save_app_finish_information
|
18
|
+
raise I18n.t('error.config.log_section_overwrite', func: 'save_app_finish_information')
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_exception(e)
|
22
|
+
@exception = e
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module CliApplication
|
2
|
+
module Log
|
3
|
+
class Config
|
4
|
+
attr_reader :log_section
|
5
|
+
attr_reader :type
|
6
|
+
|
7
|
+
# Конструктор. Вызывается при создании класса приложения. В Конструктор передается
|
8
|
+
# секция конфигурационного файла, описывающего правила логгирования приложения
|
9
|
+
# Форматы файла:
|
10
|
+
#
|
11
|
+
# Логгирование отключено (не рекомендуется)
|
12
|
+
# cli:
|
13
|
+
# log:
|
14
|
+
# type: none
|
15
|
+
#
|
16
|
+
# Логгирование в файл
|
17
|
+
# cli:
|
18
|
+
# log:
|
19
|
+
# type: file
|
20
|
+
# location: папка для храннения логов
|
21
|
+
#
|
22
|
+
# Логгирование в базу данных
|
23
|
+
# cli:
|
24
|
+
# log:
|
25
|
+
# type: database
|
26
|
+
# database: имя конфигурации базы данных
|
27
|
+
# table_name: имя таблицы. По умолчанию - st_cli_application_log
|
28
|
+
#
|
29
|
+
#
|
30
|
+
# 1. Описание хранения логов в файлах
|
31
|
+
# Если ключ location не указан, то в качестве базовой папки будет использована
|
32
|
+
# папка класса, с добавлением logs. Если папки нет - она будет создана.
|
33
|
+
# Имя файла лога - соответствует имени скрипта, с добавкой '/logs/'
|
34
|
+
# При запуске осуществляется проверка прав на указанные файлы. Если есть риск незапуска
|
35
|
+
# скрипта под другими пользователями - то будет исключение.
|
36
|
+
# Файл создается в два этапа. Первый - создается файл при запуске, с указанием даты старта
|
37
|
+
# В случае ошибки - она пишется в лог. В случае успешного завершения - запись об этом тоже пишется
|
38
|
+
# в лог
|
39
|
+
#
|
40
|
+
# 2. Описание хранения логов в базе данных
|
41
|
+
#
|
42
|
+
def initialize(config)
|
43
|
+
@possible_keys = [:none, :file, :database]
|
44
|
+
|
45
|
+
@log_section = config.cli.log
|
46
|
+
@config = config
|
47
|
+
check_section_exist
|
48
|
+
check_section_type
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
|
55
|
+
def check_section_type
|
56
|
+
@type = @log_section.type.downcase.to_sym rescue :unknown
|
57
|
+
unless @possible_keys.include?(@type)
|
58
|
+
raise I18n.t('error.config.log_section_type_wrong', filename: @config.filename, type: @type.to_s.inspect)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def check_section_exist
|
63
|
+
if @log_section.nil?
|
64
|
+
raise I18n.t('error.config.log_section_missing', filename: @config.filename)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module CliApplication
|
2
|
+
module Log
|
3
|
+
class File < CliApplication::Log::Base
|
4
|
+
attr_reader :folder
|
5
|
+
attr_reader :filename
|
6
|
+
|
7
|
+
def initialize(app, log, class_folder)
|
8
|
+
@app = app
|
9
|
+
@log = log
|
10
|
+
@class_folder = class_folder
|
11
|
+
init_log
|
12
|
+
end
|
13
|
+
|
14
|
+
def save_app_start_information
|
15
|
+
log(I18n.t('config.log_section.start_header'))
|
16
|
+
log(I18n.t('config.log_section.app_name', name: $PROGRAM_NAME))
|
17
|
+
log(I18n.t('config.log_section.app_script_name', name: ::File.basename($PROGRAM_NAME)))
|
18
|
+
log(I18n.t('config.log_section.app_started_at', time: Time.zone.now))
|
19
|
+
log("")
|
20
|
+
end
|
21
|
+
|
22
|
+
def save_app_run_information
|
23
|
+
log(I18n.t('config.log_section.run_header'))
|
24
|
+
log("")
|
25
|
+
end
|
26
|
+
|
27
|
+
def save_app_finish_information
|
28
|
+
log(I18n.t('config.log_section.finish_header'))
|
29
|
+
unless @exception.nil?
|
30
|
+
log(@exception.message)
|
31
|
+
log(@exception.backtrace.join("\n"))
|
32
|
+
end
|
33
|
+
log(I18n.t('config.log_section.app_executed_at', time: Time.zone.now, executed_at: @app.executed_at.round(3)))
|
34
|
+
log(I18n.t('config.log_section.app_memory', value: StTools::Human.memory))
|
35
|
+
log(I18n.t('config.log_section.app_exitcode', exitcode: @app.exitcode, status: ((@app.exitcode == 0 ? 'SUCCESS' : 'FAIL'))))
|
36
|
+
end
|
37
|
+
|
38
|
+
def log(message)
|
39
|
+
::File.open(@filename, 'a') {|f| f.write message + "\n" }
|
40
|
+
::File.chmod(0777, @filename)
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
|
47
|
+
def init_log
|
48
|
+
init_names
|
49
|
+
create_folder
|
50
|
+
check_folder_and_file
|
51
|
+
end
|
52
|
+
|
53
|
+
# Проверка на доступность папки и файла. Если с этим проблема,
|
54
|
+
# то выбрасываем исключение, чтобы уже на этапе отладки было понятно, что
|
55
|
+
# при запуске приложения из под cron будут проблемы
|
56
|
+
def check_folder_and_file
|
57
|
+
if ::File.exists?(@filename)
|
58
|
+
delete_file
|
59
|
+
else
|
60
|
+
check_folder
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Проверка на возможность дописывать в вфайл из под любого пользователя
|
65
|
+
# Если права не XXX, то выбрасываем исключение
|
66
|
+
def delete_file
|
67
|
+
::File.delete(@filename)
|
68
|
+
end
|
69
|
+
|
70
|
+
def check_folder
|
71
|
+
if Dir.exists?(@folder)
|
72
|
+
# s = Dir.stat(@filename)
|
73
|
+
# puts "Dir >>>>>>>>>>>>>>>>>> #{s.mode}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def create_folder
|
78
|
+
unless Dir.exists?(@folder)
|
79
|
+
Dir.mkdir(@folder, 0777)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def init_names
|
84
|
+
if @log.log_section.location.nil?
|
85
|
+
# Локация не задана
|
86
|
+
@folder = ::File.join(@class_folder, 'logs')
|
87
|
+
else
|
88
|
+
# Локация в конфиге задана
|
89
|
+
@folder = @log.log_section.location
|
90
|
+
end
|
91
|
+
@filename = ::File.join(@folder, ::File.basename($PROGRAM_NAME, '.rb')+'.log')
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module CliApplication
|
2
|
+
module Log
|
3
|
+
class None < CliApplication::Log::Base
|
4
|
+
|
5
|
+
def log(message)
|
6
|
+
end
|
7
|
+
|
8
|
+
def save_app_start_information
|
9
|
+
end
|
10
|
+
|
11
|
+
def save_app_run_information
|
12
|
+
end
|
13
|
+
|
14
|
+
def save_app_finish_information
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/cli_application/stat.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
1
|
module CliApplication
|
2
|
-
class Stat
|
2
|
+
class Stat # :nodoc:
|
3
3
|
attr_reader :stat
|
4
4
|
|
5
|
+
|
5
6
|
def initialize(folders)
|
6
7
|
@stat_filename = File.join([folders[:class], 'stat', ::StTools::System.exename.gsub(/\.rb$/, '.yml')])
|
7
|
-
@stat_folder
|
8
|
+
@stat_folder = File.join([folders[:class], 'stat'])
|
8
9
|
create_folder
|
9
10
|
|
10
11
|
init_stat
|
11
|
-
folders[:stat]
|
12
|
+
folders[:stat] = @stat_folder
|
12
13
|
@stat[:folders] = folders
|
13
14
|
|
14
15
|
@prev = load_stat
|
15
16
|
end
|
16
17
|
|
18
|
+
|
17
19
|
#-------------------------------------------------------------
|
18
20
|
#
|
19
21
|
# Функции настройки приложения
|
@@ -23,36 +25,38 @@ module CliApplication
|
|
23
25
|
@stat[:last][:exitcode] = code
|
24
26
|
end
|
25
27
|
|
28
|
+
|
26
29
|
def executed_at=(at)
|
27
30
|
@stat[:last][:executed_at] = at
|
28
31
|
end
|
29
32
|
|
33
|
+
|
30
34
|
def last_started_at=(at)
|
31
35
|
@stat[:last][:started_at] = at.to_s
|
32
|
-
@stat[:last_started_at]
|
36
|
+
@stat[:last_started_at] = at.to_s
|
33
37
|
end
|
34
38
|
|
39
|
+
|
35
40
|
def version=(val)
|
36
41
|
@stat[:version] = val
|
37
42
|
end
|
38
43
|
|
44
|
+
|
39
45
|
def description=(val)
|
40
46
|
@stat[:description] = val
|
41
47
|
end
|
42
48
|
|
49
|
+
|
43
50
|
def shortdescription=(val)
|
44
51
|
@stat[:shortdescription] = val
|
45
52
|
end
|
46
53
|
|
54
|
+
|
47
55
|
def releasedate=(val)
|
48
56
|
@stat[:releasedate] = val
|
49
57
|
end
|
50
58
|
|
51
59
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
60
|
def last_started_at_human
|
57
61
|
res = last_started_at
|
58
62
|
if res.nil? || res == ''
|
@@ -62,45 +66,62 @@ module CliApplication
|
|
62
66
|
end
|
63
67
|
end
|
64
68
|
|
69
|
+
|
65
70
|
def startes_human
|
66
71
|
res = @prev[:avg][:starts]
|
67
72
|
"Всего было #{res} запусков"
|
68
73
|
end
|
69
74
|
|
75
|
+
|
70
76
|
def last_started_at
|
71
77
|
@prev[:last][:started_at] || ::Time.zone.now
|
72
78
|
end
|
73
79
|
|
80
|
+
|
74
81
|
def load_stat
|
75
|
-
YAML.load_file(@stat_filename)
|
82
|
+
res = YAML.load_file(@stat_filename, {})
|
83
|
+
res.empty? ? Marshal.load(Marshal.dump(init_stat)) : res
|
76
84
|
rescue
|
77
|
-
Marshal.load(
|
85
|
+
Marshal.load(Marshal.dump(init_stat))
|
78
86
|
end
|
79
87
|
|
88
|
+
|
80
89
|
def save
|
81
90
|
@prev = load_stat
|
82
91
|
update_stat
|
83
|
-
File.open(@stat_filename, 'w') {|f| f.write @prev.to_yaml }
|
92
|
+
File.open(@stat_filename, 'w') { |f| f.write @prev.to_yaml }
|
84
93
|
end
|
85
94
|
|
95
|
+
|
86
96
|
def create_folder
|
87
97
|
unless Dir.exist?(@stat_folder)
|
88
98
|
Dir.mkdir(@stat_folder, 0777)
|
89
99
|
end
|
100
|
+
|
101
|
+
# ToDo убрать в модуль Log
|
102
|
+
# 2018-01-06, добавляем проверку на доступность папки и файла. Если с этим проблема,
|
103
|
+
# то выбрасываем исключение, чтобы уже на этапе отладки было понятно, что
|
104
|
+
# при запуске приложения из под cron будут проблемы
|
105
|
+
if File.exist?(@stat_filename)
|
106
|
+
s = File.stat(@stat_filename)
|
107
|
+
puts ">>>>>>>>>>>>>>>>>> #{s.mode}"
|
108
|
+
end
|
90
109
|
end
|
91
110
|
|
111
|
+
|
92
112
|
def timezone=(val)
|
93
113
|
@stat[:timezone] = val
|
94
114
|
end
|
95
115
|
|
116
|
+
|
96
117
|
def update_stat
|
97
|
-
@prev[:name]
|
118
|
+
@prev[:name] = @stat[:name]
|
98
119
|
@prev[:shortdescription] = @stat[:shortdescription]
|
99
|
-
@prev[:version]
|
100
|
-
@prev[:releasedate]
|
101
|
-
@prev[:timezone]
|
102
|
-
@prev[:last_started_at]
|
103
|
-
@prev[:folders]
|
120
|
+
@prev[:version] = @stat[:version]
|
121
|
+
@prev[:releasedate] = @stat[:releasedate]
|
122
|
+
@prev[:timezone] = ::Time.zone.name
|
123
|
+
@prev[:last_started_at] = @stat[:last_started_at]
|
124
|
+
@prev[:folders] = @stat[:folders]
|
104
125
|
|
105
126
|
make_averages(@prev[:avg])
|
106
127
|
make_last(@prev[:last])
|
@@ -112,58 +133,61 @@ module CliApplication
|
|
112
133
|
tmp << @prev[:last][:memory]
|
113
134
|
|
114
135
|
@prev[:last10].unshift(tmp.join(','))
|
115
|
-
@prev[:last10] = @prev[:last10][0,10]
|
136
|
+
@prev[:last10] = @prev[:last10][0, 10]
|
116
137
|
end
|
117
138
|
|
139
|
+
|
118
140
|
def init_stat
|
119
|
-
@stat
|
120
|
-
@stat[:name]
|
141
|
+
@stat = Hash.new
|
142
|
+
@stat[:name] = ::StTools::System.exename
|
121
143
|
@stat[:shortdescription] = ''
|
122
|
-
@stat[:version]
|
123
|
-
@stat[:releasedate]
|
124
|
-
@stat[:timezone]
|
125
|
-
@stat[:last_started_at]
|
126
|
-
@stat[:folders]
|
127
|
-
|
128
|
-
@stat[:avg]
|
129
|
-
@stat[:avg][:starts]
|
130
|
-
@stat[:avg][:executed_at]
|
144
|
+
@stat[:version] = ''
|
145
|
+
@stat[:releasedate] = ''
|
146
|
+
@stat[:timezone] = ''
|
147
|
+
@stat[:last_started_at] = ''
|
148
|
+
@stat[:folders] = @folders
|
149
|
+
|
150
|
+
@stat[:avg] = Hash.new
|
151
|
+
@stat[:avg][:starts] = 0
|
152
|
+
@stat[:avg][:executed_at] = 0
|
131
153
|
@stat[:avg][:executed_at_human] = ''
|
132
|
-
@stat[:avg][:memory]
|
154
|
+
@stat[:avg][:memory] = 0
|
133
155
|
|
134
|
-
@stat[:last]
|
135
|
-
@stat[:last][:started_at]
|
136
|
-
@stat[:last][:executed_at]
|
156
|
+
@stat[:last] = Hash.new
|
157
|
+
@stat[:last][:started_at] = nil
|
158
|
+
@stat[:last][:executed_at] = 0
|
137
159
|
@stat[:last][:executed_at_human] = ''
|
138
|
-
@stat[:last][:memory]
|
139
|
-
@stat[:last][:exitcode]
|
160
|
+
@stat[:last][:memory] = ''
|
161
|
+
@stat[:last][:exitcode] = 0
|
140
162
|
|
141
163
|
@stat[:last10] = Array.new
|
142
164
|
|
143
165
|
@stat
|
144
166
|
end
|
145
167
|
|
168
|
+
|
146
169
|
def make_averages(avg)
|
147
170
|
if avg[:starts] == 0
|
148
|
-
avg[:starts]
|
149
|
-
avg[:executed_at]
|
171
|
+
avg[:starts] = 1
|
172
|
+
avg[:executed_at] = @stat[:last][:executed_at]
|
150
173
|
avg[:executed_at_human] = ::StTools::Human.ago_in_words_pair(avg[:executed_at].to_i).join(' ')
|
151
|
-
avg[:memory]
|
174
|
+
avg[:memory] = ::StTools::System.memory.to_i
|
152
175
|
else
|
153
|
-
mul
|
154
|
-
avg[:starts]
|
155
|
-
avg[:executed_at]
|
176
|
+
mul = avg[:starts]
|
177
|
+
avg[:starts] += 1
|
178
|
+
avg[:executed_at] = ((avg[:executed_at] * mul + @stat[:last][:executed_at]).to_f / avg[:starts]).round(6)
|
156
179
|
avg[:executed_at_human] = ::StTools::Human.ago_in_words_pair(avg[:executed_at]).join(' ')
|
157
|
-
avg[:memory]
|
180
|
+
avg[:memory] = (avg[:memory] * mul + ::StTools::System.memory).to_i / avg[:starts]
|
158
181
|
end
|
159
182
|
end
|
160
183
|
|
184
|
+
|
161
185
|
def make_last(last)
|
162
|
-
last[:started_at]
|
163
|
-
last[:executed_at]
|
186
|
+
last[:started_at] = @stat[:last_started_at]
|
187
|
+
last[:executed_at] = @stat[:last][:executed_at]
|
164
188
|
last[:executed_at_human] = ::StTools::Human.ago_in_words_pair(last[:executed_at]).join(' ')
|
165
|
-
last[:memory]
|
166
|
-
last[:exitcode]
|
189
|
+
last[:memory] = ::StTools::Human.memory
|
190
|
+
last[:exitcode] = @stat[:last][:exitcode]
|
167
191
|
end
|
168
192
|
|
169
193
|
end
|
@@ -1,33 +1,21 @@
|
|
1
1
|
---
|
2
2
|
:name: app.rb
|
3
|
-
:shortdescription:
|
4
|
-
:version: '
|
5
|
-
:releasedate: '
|
3
|
+
:shortdescription: ''
|
4
|
+
:version: ''
|
5
|
+
:releasedate: ''
|
6
6
|
:timezone: Moscow
|
7
|
-
:last_started_at: '
|
8
|
-
:folders:
|
9
|
-
:app: "/Users/Stan/Documents/Development/RubyMine/cli_application/test/examples/2"
|
10
|
-
:class: "/Users/Stan/Documents/Development/RubyMine/cli_application/test/examples/1"
|
11
|
-
:stat: "/Users/Stan/Documents/Development/RubyMine/cli_application/test/examples/1/stat"
|
7
|
+
:last_started_at: ''
|
8
|
+
:folders:
|
12
9
|
:avg:
|
13
|
-
:starts:
|
14
|
-
:executed_at:
|
15
|
-
:executed_at_human:
|
16
|
-
:memory:
|
10
|
+
:starts: 1
|
11
|
+
:executed_at: 0
|
12
|
+
:executed_at_human: 0 секунд
|
13
|
+
:memory: 44269568
|
17
14
|
:last:
|
18
|
-
:started_at: '
|
19
|
-
:executed_at: 0
|
20
|
-
:executed_at_human: 0
|
21
|
-
:memory:
|
22
|
-
:exitcode:
|
15
|
+
:started_at: ''
|
16
|
+
:executed_at: 0
|
17
|
+
:executed_at_human: 0 секунд
|
18
|
+
:memory: 42.2 Мбайт
|
19
|
+
:exitcode: 0
|
23
20
|
:last10:
|
24
|
-
-
|
25
|
-
- 2017-01-04 12:18:26 +0300,255,0.053526,41.2 Мбайт
|
26
|
-
- 2015-11-12 08:04:04 +0300,10,0.032581,35 кбайт
|
27
|
-
- 2015-10-26 22:16:55 +0300,0,0.029927,36 кбайт
|
28
|
-
- 2015-10-26 22:16:01 +0300,0,0.02892,36 кбайт
|
29
|
-
- 2015-10-26 22:10:40 +0300,0,0.033229,36 кбайт
|
30
|
-
- 2015-10-26 22:10:25 +0300,0,0.036708,36 кбайт
|
31
|
-
- 2015-10-26 22:08:56 +0300,0,0.036485,38 кбайт
|
32
|
-
- 2015-10-26 22:07:56 +0300,0,0.035323,36 кбайт
|
33
|
-
- 2015-10-26 22:04:20 +0300,255,0.053609,35 кбайт
|
21
|
+
- ",0,0,42.2 Мбайт"
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#encoding: utf-8
|
3
|
+
require './cli_example.rb'
|
4
|
+
|
5
|
+
class TestApp < CliExample
|
6
|
+
|
7
|
+
def main
|
8
|
+
puts "Hello, world!"
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
app = TestApp.new(ARGV, __dir__)
|
14
|
+
|
15
|
+
app.version = '1.0'
|
16
|
+
app.releasedate = '2018-01-06'
|
17
|
+
app.shortdescription = 'Тестовый скрипт демонстрации CliApplication'
|
18
|
+
app.description = "CliApplication gem демо. #{app.shortdescription}"
|
19
|
+
|
20
|
+
app.help
|
21
|
+
|
22
|
+
app.run
|
23
|
+
exit(app.exitcode)
|
24
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#encoding: utf-8
|
3
|
+
require './cli_example.rb'
|
4
|
+
|
5
|
+
class TestApp < CliExample
|
6
|
+
|
7
|
+
def main
|
8
|
+
puts "Hello, world!"
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
app = TestApp.new(ARGV, __dir__)
|
14
|
+
|
15
|
+
app.version = '1.0'
|
16
|
+
app.releasedate = '2018-01-06'
|
17
|
+
app.shortdescription = 'Тестовый скрипт демонстрации CliApplication'
|
18
|
+
app.description = "CliApplication gem демо. #{app.shortdescription}"
|
19
|
+
|
20
|
+
app.help
|
21
|
+
|
22
|
+
app.run
|
23
|
+
exit(app.exitcode)
|
24
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
---
|
2
|
+
:name: app.rb
|
3
|
+
:shortdescription: ''
|
4
|
+
:version: ''
|
5
|
+
:releasedate: ''
|
6
|
+
:timezone: Moscow
|
7
|
+
:last_started_at: ''
|
8
|
+
:folders:
|
9
|
+
:avg:
|
10
|
+
:starts: 1
|
11
|
+
:executed_at: 0
|
12
|
+
:executed_at_human: 0 секунд
|
13
|
+
:memory: 41975808
|
14
|
+
:last:
|
15
|
+
:started_at: ''
|
16
|
+
:executed_at: 0
|
17
|
+
:executed_at_human: 0 секунд
|
18
|
+
:memory: 40.0 Мбайт
|
19
|
+
:exitcode: 0
|
20
|
+
:last10:
|
21
|
+
- ",0,0,40.0 Мбайт"
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#encoding: utf-8
|
3
|
+
require './cli_example.rb'
|
4
|
+
|
5
|
+
class TestApp < CliExample
|
6
|
+
|
7
|
+
def main
|
8
|
+
puts "Hello, world!"
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
app = TestApp.new(ARGV, __dir__)
|
14
|
+
|
15
|
+
app.version = '1.0'
|
16
|
+
app.releasedate = '2018-01-06'
|
17
|
+
app.shortdescription = 'Тестовый скрипт демонстрации CliApplication'
|
18
|
+
app.description = "CliApplication gem демо. #{app.shortdescription}"
|
19
|
+
|
20
|
+
app.help
|
21
|
+
|
22
|
+
app.run
|
23
|
+
exit(app.exitcode)
|
24
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
---
|
2
|
+
:name: app.rb
|
3
|
+
:shortdescription: "Тестовый скрипт демонстрации CliApplication"
|
4
|
+
:version: '1.0'
|
5
|
+
:releasedate: '2018-01-06'
|
6
|
+
:timezone: Moscow
|
7
|
+
:last_started_at: '2018-01-06 23:26:28 +0300'
|
8
|
+
:folders:
|
9
|
+
:app: "/Users/Stan/Documents/Development/RubyMine/cli_application/test/log/03_log_section_type_none_ok"
|
10
|
+
:class: "/Users/Stan/Documents/Development/RubyMine/cli_application/test/log/03_log_section_type_none_ok"
|
11
|
+
:stat: "/Users/Stan/Documents/Development/RubyMine/cli_application/test/log/03_log_section_type_none_ok/stat"
|
12
|
+
:avg:
|
13
|
+
:starts: 3
|
14
|
+
:executed_at: 0.040108
|
15
|
+
:executed_at_human: 0.040108 секунд
|
16
|
+
:memory: 41891157
|
17
|
+
:last:
|
18
|
+
:started_at: '2018-01-06 23:26:28 +0300'
|
19
|
+
:executed_at: 0.054604
|
20
|
+
:executed_at_human: 0.054604 секунд
|
21
|
+
:memory: 40.1 Мбайт
|
22
|
+
:exitcode: 255
|
23
|
+
:last10:
|
24
|
+
- 2018-01-06 23:26:28 +0300,255,0.054604,40.1 Мбайт
|
25
|
+
- 2018-01-06 20:20:48 +0300,255,0.06572,39.7 Мбайт
|
26
|
+
- ",0,0,40.0 Мбайт"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#encoding: utf-8
|
3
|
+
require './cli_example.rb'
|
4
|
+
|
5
|
+
class TestApp < CliExample
|
6
|
+
|
7
|
+
def main
|
8
|
+
puts "Hello, world!"
|
9
|
+
0
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
app = TestApp.new(ARGV, __dir__)
|
15
|
+
|
16
|
+
app.version = '1.0'
|
17
|
+
app.releasedate = '2018-01-06'
|
18
|
+
app.shortdescription = 'Тестовый скрипт демонстрации CliApplication'
|
19
|
+
app.description = "CliApplication gem демо. #{app.shortdescription}"
|
20
|
+
|
21
|
+
app.help
|
22
|
+
|
23
|
+
app.run
|
24
|
+
exit(app.exitcode)
|
25
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
-- Запуск приложения ---------------------------
|
2
|
+
Приложение: /Users/Stan/Documents/Development/RubyMine/cli_application/test/log/04_log_section_type_file_ok/app.rb
|
3
|
+
Имя скрипта: app.rb
|
4
|
+
Приложение запущено: 2018-01-07 16:47:13 +0300
|
5
|
+
|
6
|
+
-- Пользовательская секция ---------------------
|
7
|
+
|
8
|
+
-- Завершение приложения -----------------------
|
9
|
+
Приложение завершено: 2018-01-07 16:47:13 +0300 (время выполнения: 0.045 сек.)
|
10
|
+
Использование памяти: 40.0 Мбайт
|
11
|
+
Результат завершения: 0 (SUCCESS)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
---
|
2
|
+
:name: app.rb
|
3
|
+
:shortdescription: "Тестовый скрипт демонстрации CliApplication"
|
4
|
+
:version: '1.0'
|
5
|
+
:releasedate: '2018-01-06'
|
6
|
+
:timezone: Moscow
|
7
|
+
:last_started_at: '2018-01-07 16:47:13 +0300'
|
8
|
+
:folders:
|
9
|
+
:app: "/Users/Stan/Documents/Development/RubyMine/cli_application/test/log/04_log_section_type_file_ok"
|
10
|
+
:class: "/Users/Stan/Documents/Development/RubyMine/cli_application/test/log/04_log_section_type_file_ok"
|
11
|
+
:stat: "/Users/Stan/Documents/Development/RubyMine/cli_application/test/log/04_log_section_type_file_ok/stat"
|
12
|
+
:avg:
|
13
|
+
:starts: 21
|
14
|
+
:executed_at: 0.062094
|
15
|
+
:executed_at_human: 0.062094 секунд
|
16
|
+
:memory: 41897590
|
17
|
+
:last:
|
18
|
+
:started_at: '2018-01-07 16:47:13 +0300'
|
19
|
+
:executed_at: 0.044499
|
20
|
+
:executed_at_human: 0.044499 секунд
|
21
|
+
:memory: 40.0 Мбайт
|
22
|
+
:exitcode: 0
|
23
|
+
:last10:
|
24
|
+
- 2018-01-07 16:47:13 +0300,0,0.044499,40.0 Мбайт
|
25
|
+
- 2018-01-07 00:00:13 +0300,0,0.066548,40.4 Мбайт
|
26
|
+
- 2018-01-06 23:59:57 +0300,255,0.089557,39.7 Мбайт
|
27
|
+
- 2018-01-06 23:54:52 +0300,255,0.088694,40.0 Мбайт
|
28
|
+
- 2018-01-06 23:51:19 +0300,255,0.085997,39.9 Мбайт
|
29
|
+
- 2018-01-06 23:32:03 +0300,255,0.051075,40.2 Мбайт
|
30
|
+
- 2018-01-06 23:30:44 +0300,255,0.075102,39.7 Мбайт
|
31
|
+
- 2018-01-06 23:27:03 +0300,255,0.079105,40.1 Мбайт
|
32
|
+
- 2018-01-06 23:24:07 +0300,255,0.056074,40.1 Мбайт
|
33
|
+
- 2018-01-06 23:23:17 +0300,255,0.057794,40.2 Мбайт
|
metadata
CHANGED
@@ -1,61 +1,61 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cli_application
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stan Zhuravlev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.9'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.9'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '10.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: st_tools
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0.4'
|
48
|
-
- - "
|
48
|
+
- - ">"
|
49
49
|
- !ruby/object:Gem::Version
|
50
50
|
version: '0.4'
|
51
51
|
type: :development
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
54
54
|
requirements:
|
55
|
-
- - "
|
55
|
+
- - "~>"
|
56
56
|
- !ruby/object:Gem::Version
|
57
57
|
version: '0.4'
|
58
|
-
- - "
|
58
|
+
- - ">"
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: '0.4'
|
61
61
|
- !ruby/object:Gem::Dependency
|
@@ -100,6 +100,13 @@ files:
|
|
100
100
|
- lib/cli_application/databases.rb
|
101
101
|
- lib/cli_application/includes.rb
|
102
102
|
- lib/cli_application/json_struct.rb
|
103
|
+
- lib/cli_application/locales/ru.yml
|
104
|
+
- lib/cli_application/log/README.md
|
105
|
+
- lib/cli_application/log/base.rb
|
106
|
+
- lib/cli_application/log/config.rb
|
107
|
+
- lib/cli_application/log/database.rb
|
108
|
+
- lib/cli_application/log/file.rb
|
109
|
+
- lib/cli_application/log/none.rb
|
103
110
|
- lib/cli_application/mail.rb
|
104
111
|
- lib/cli_application/mail_lib/base.rb
|
105
112
|
- lib/cli_application/mail_lib/error.rb
|
@@ -123,6 +130,18 @@ files:
|
|
123
130
|
- test/examples/7/app.rb
|
124
131
|
- test/examples/7/mail/app-mail-2015-06-10.txt
|
125
132
|
- test/examples/8/app.rb
|
133
|
+
- test/log/01_log_section_missing/app.rb
|
134
|
+
- test/log/01_log_section_missing/cli_example.rb
|
135
|
+
- test/log/02_log_section_type_wrong/app.rb
|
136
|
+
- test/log/02_log_section_type_wrong/cli_example.rb
|
137
|
+
- test/log/02_log_section_type_wrong/stat/app.yml
|
138
|
+
- test/log/03_log_section_type_none_ok/app.rb
|
139
|
+
- test/log/03_log_section_type_none_ok/cli_example.rb
|
140
|
+
- test/log/03_log_section_type_none_ok/stat/app.yml
|
141
|
+
- test/log/04_log_section_type_file_ok/app.rb
|
142
|
+
- test/log/04_log_section_type_file_ok/cli_example.rb
|
143
|
+
- test/log/04_log_section_type_file_ok/logs/app.log
|
144
|
+
- test/log/04_log_section_type_file_ok/stat/app.yml
|
126
145
|
- test/stat/rdebug-ide
|
127
146
|
- test/stat/test_app.yml
|
128
147
|
- test/test_app.rb
|