Class: Trifle::Logs::Driver::File

Inherits:
Object
  • Object
show all
Defined in:
lib/trifle/logs/driver/file.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path:, suffix: '%Y/%m/%d', read_size: 100) ⇒ File

Returns a new instance of File.



11
12
13
14
15
# File 'lib/trifle/logs/driver/file.rb', line 11

def initialize(path:, suffix: '%Y/%m/%d', read_size: 100)
  @path = path
  @suffix = suffix
  @read_size = read_size
end

Instance Attribute Details

#pathObject

Returns the value of attribute path.



9
10
11
# File 'lib/trifle/logs/driver/file.rb', line 9

def path
  @path
end

#read_sizeObject

Returns the value of attribute read_size.



9
10
11
# File 'lib/trifle/logs/driver/file.rb', line 9

def read_size
  @read_size
end

#suffixObject

Returns the value of attribute suffix.



9
10
11
# File 'lib/trifle/logs/driver/file.rb', line 9

def suffix
  @suffix
end

Instance Method Details

#dump(message, namespace:) ⇒ Object



32
33
34
35
36
37
# File 'lib/trifle/logs/driver/file.rb', line 32

def dump(message, namespace:)
  locked_file(namespace: namespace) do |file|
    file.write("#{message}\n")
  end
  message
end

#file_for(files, file_loc: nil) ⇒ Object



116
117
118
119
120
121
122
123
124
# File 'lib/trifle/logs/driver/file.rb', line 116

def file_for(files, file_loc: nil)
  latest = files.last
  return [latest, length_of(latest), length_of(latest)] unless file_loc

  file, line = file_loc.split('#')
  return [latest, length_of(latest), length_of(latest)] unless files.include?(file)

  [file, line.to_i, length_of(latest)]
end

#filename_for(namespace:) ⇒ Object



17
18
19
# File 'lib/trifle/logs/driver/file.rb', line 17

def filename_for(namespace:)
  "#{path}/#{namespace}/#{Time.now.strftime(suffix)}.log"
end

#files_for(namespace:) ⇒ Object



126
127
128
# File 'lib/trifle/logs/driver/file.rb', line 126

def files_for(namespace:)
  Dir.glob("#{path}/#{namespace}/**/*.log").sort
end

#length_of(file) ⇒ Object



130
131
132
# File 'lib/trifle/logs/driver/file.rb', line 130

def length_of(file)
  `wc -l #{file}`.split.first.to_i
end

#locked_file(namespace:, &block) ⇒ Object



21
22
23
24
25
26
27
28
29
30
# File 'lib/trifle/logs/driver/file.rb', line 21

def locked_file(namespace:, &block)
  filename = filename_for(namespace: namespace)
  FileUtils.mkdir_p(::File.dirname(filename))
  ::File.open(filename, 'a') do |file|
    file.flock(::File::LOCK_EX)
    block.call(file)
  ensure
    file.flock(::File::LOCK_UN)
  end
end

#next_file_for(files, file) ⇒ Object



108
109
110
111
112
113
114
# File 'lib/trifle/logs/driver/file.rb', line 108

def next_file_for(files, file)
  idx = files.index(file)
  return [nil, nil, nil] if idx == files.length - 1 # next file doesnt exist

  file = files[idx + 1]
  [file, 1, length_of(file)]
end

#prev_file_for(files, file) ⇒ Object



100
101
102
103
104
105
106
# File 'lib/trifle/logs/driver/file.rb', line 100

def prev_file_for(files, file)
  idx = files.index(file)
  return [nil, nil, nil] if idx.zero? # prev file doesnt exist

  file = files[idx - 1]
  [file, length_of(file), length_of(file)]
end

#read(file, from, to, pattern) ⇒ Object



92
93
94
95
96
97
98
# File 'lib/trifle/logs/driver/file.rb', line 92

def read(file, from, to, pattern)
  # sed -n '2,4p;5q' test/lolz/2022/09_06.log | rg '.*' --json
  # head -4 test/lolz/2022/09_06.log | tail +2 | rg '.*' --json
  cmd = "sed -n '#{from},#{to}p;#{to + 1}q' #{file} | rg '#{pattern || '.*'}' --json"
  _stdin, stdout, _stderr = Open3.popen3(cmd)
  stdout.map { |l| JSON.parse(l) }
end

#search(namespace:, pattern:, file_loc: nil, direction: nil) ⇒ Object



39
40
41
42
43
44
# File 'lib/trifle/logs/driver/file.rb', line 39

def search(namespace:, pattern:, file_loc: nil, direction: nil)
  files = files_for(namespace: namespace)
  return Trifle::Logs::Result.new if files.count.zero?

  send("search_#{direction}_in_file", files, file_loc, pattern)
end

#search__in_file(files, file_loc, pattern) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
# File 'lib/trifle/logs/driver/file.rb', line 46

def search__in_file(files, file_loc, pattern)
  file, _line, length = file_for(files, file_loc: file_loc)

  min_line = [length - read_size, 1].max
  max_line = length

  Trifle::Logs::Result.new(
    read(file, min_line, max_line, pattern),
    min_loc: "#{file}##{min_line}", max_loc: "#{file}##{max_line}"
  )
end

#search_next_in_file(files, file_loc, pattern) ⇒ Object

rubocop:disable Metrics/MethodLength



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/trifle/logs/driver/file.rb', line 58

def search_next_in_file(files, file_loc, pattern) # rubocop:disable Metrics/MethodLength
  file, line, length = file_for(files, file_loc: file_loc)
  if line == length
    cfile, cline, clength = next_file_for(files, file) if line == length
    return Trifle::Logs::Result.new(max_loc: "#{file}##{line}") if cfile.nil?

    file, line, length = cfile, cline, clength # rubocop:disable Style/ParallelAssignment
  end

  max_line = [line + read_size, length].min

  Trifle::Logs::Result.new(
    read(file, line, max_line, pattern),
    max_loc: "#{file}##{max_line}"
  )
end

#search_prev_in_file(files, file_loc, pattern) ⇒ Object

rubocop:disable Metrics/MethodLength



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/trifle/logs/driver/file.rb', line 75

def search_prev_in_file(files, file_loc, pattern) # rubocop:disable Metrics/MethodLength
  file, line, _length = file_for(files, file_loc: file_loc)
  if line == 1
    cfile, cline, clength = prev_file_for(files, file)
    return Trifle::Logs::Result.new(min_loc: "#{file}##{line}") if cfile.nil?

    file, line, _length = cfile, cline, clength # rubocop:disable Style/ParallelAssignment
  end

  min_line = [line - read_size, 1].max

  Trifle::Logs::Result.new(
    read(file, min_line, line, pattern),
    min_loc: "#{file}##{min_line}"
  )
end