vector_mcp 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,157 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fileutils"
4
- require "date"
5
-
6
- module VectorMCP
7
- module Logging
8
- module Outputs
9
- class File < Base
10
- def initialize(config = {})
11
- super
12
- @path = @config[:path] or raise OutputError, "File path required"
13
- @max_size = parse_size(@config[:max_size] || "100MB")
14
- @max_files = @config[:max_files] || 7
15
- @rotation = @config[:rotation] || "daily"
16
- @mutex = Mutex.new
17
- @file = nil
18
- @current_date = nil
19
-
20
- ensure_directory_exists
21
- open_file
22
- end
23
-
24
- def close
25
- @mutex.synchronize do
26
- @file&.close
27
- @file = nil
28
- end
29
- super
30
- end
31
-
32
- protected
33
-
34
- def write_formatted(message)
35
- @mutex.synchronize do
36
- rotate_if_needed
37
- @file.write(message)
38
- @file.flush
39
- end
40
- end
41
-
42
- private
43
-
44
- def ensure_directory_exists
45
- dir = ::File.dirname(@path)
46
- FileUtils.mkdir_p(dir) unless ::File.directory?(dir)
47
- rescue StandardError => e
48
- raise OutputError, "Cannot create log directory #{dir}: #{e.message}"
49
- end
50
-
51
- def open_file
52
- @file = ::File.open(current_log_path, "a")
53
- @file.sync = true
54
- @current_date = Date.today if daily_rotation?
55
- rescue StandardError => e
56
- raise OutputError, "Cannot open log file #{current_log_path}: #{e.message}"
57
- end
58
-
59
- def current_log_path
60
- if daily_rotation?
61
- base, ext = split_path(@path)
62
- "#{base}_#{Date.today.strftime("%Y%m%d")}#{ext}"
63
- else
64
- @path
65
- end
66
- end
67
-
68
- def rotate_if_needed
69
- return unless should_rotate?
70
-
71
- rotate_file
72
- open_file
73
- end
74
-
75
- def should_rotate?
76
- return false unless @file
77
-
78
- case @rotation
79
- when "daily"
80
- daily_rotation? && @current_date != Date.today
81
- when "size"
82
- @file.size >= @max_size
83
- else
84
- false
85
- end
86
- end
87
-
88
- def rotate_file
89
- @file&.close
90
-
91
- if daily_rotation?
92
- cleanup_old_files
93
- else
94
- rotate_numbered_files
95
- end
96
- end
97
-
98
- def daily_rotation?
99
- @rotation == "daily"
100
- end
101
-
102
- def rotate_numbered_files
103
- return unless ::File.exist?(@path)
104
-
105
- (@max_files - 1).downto(1) do |i|
106
- old_file = "#{@path}.#{i}"
107
- new_file = "#{@path}.#{i + 1}"
108
-
109
- ::File.rename(old_file, new_file) if ::File.exist?(old_file)
110
- end
111
-
112
- ::File.rename(@path, "#{@path}.1")
113
- end
114
-
115
- def cleanup_old_files
116
- base, ext = split_path(@path)
117
- pattern = "#{base}_*#{ext}"
118
-
119
- old_files = Dir.glob(pattern).reverse
120
- files_to_remove = old_files[@max_files..] || []
121
-
122
- files_to_remove.each do |file|
123
- ::File.unlink(file)
124
- rescue StandardError => e
125
- fallback_write("Warning: Could not remove old log file #{file}: #{e.message}\n")
126
- end
127
- end
128
-
129
- def split_path(path)
130
- ext = ::File.extname(path)
131
- base = path.chomp(ext)
132
- [base, ext]
133
- end
134
-
135
- def parse_size(size_str)
136
- size_str = size_str.to_s.upcase
137
-
138
- raise OutputError, "Invalid size format: #{size_str}" unless size_str =~ /\A(\d+)(KB|MB|GB)?\z/
139
-
140
- number = ::Regexp.last_match(1).to_i
141
- unit = ::Regexp.last_match(2) || "B"
142
-
143
- case unit
144
- when "KB"
145
- number * 1024
146
- when "MB"
147
- number * 1024 * 1024
148
- when "GB"
149
- number * 1024 * 1024 * 1024
150
- else
151
- number
152
- end
153
- end
154
- end
155
- end
156
- end
157
- end
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "logging/constants"
4
- require_relative "logging/core"
5
- require_relative "logging/configuration"
6
- require_relative "logging/component"
7
- require_relative "logging/formatters/base"
8
- require_relative "logging/formatters/text"
9
- require_relative "logging/formatters/json"
10
- require_relative "logging/outputs/base"
11
- require_relative "logging/outputs/console"
12
- require_relative "logging/outputs/file"
13
- require_relative "logging/filters/level"
14
- require_relative "logging/filters/component"
15
-
16
- module VectorMCP
17
- module Logging
18
- class Error < StandardError; end
19
- class ConfigurationError < Error; end
20
- class FormatterError < Error; end
21
- class OutputError < Error; end
22
-
23
- LEVELS = {
24
- TRACE: 0,
25
- DEBUG: 1,
26
- INFO: 2,
27
- WARN: 3,
28
- ERROR: 4,
29
- FATAL: 5,
30
- SECURITY: 6
31
- }.freeze
32
-
33
- LEVEL_NAMES = LEVELS.invert.freeze
34
-
35
- def self.level_name(level)
36
- (LEVEL_NAMES[level] || "UNKNOWN").to_s
37
- end
38
-
39
- def self.level_value(name)
40
- LEVELS[name.to_s.upcase.to_sym] || LEVELS[:INFO]
41
- end
42
-
43
- class LogEntry
44
- attr_reader :timestamp, :level, :component, :message, :context, :thread_id
45
-
46
- def initialize(attributes = {})
47
- @timestamp = attributes[:timestamp]
48
- @level = attributes[:level]
49
- @component = attributes[:component]
50
- @message = attributes[:message]
51
- @context = attributes[:context] || {}
52
- @thread_id = attributes[:thread_id]
53
- end
54
-
55
- def level_name
56
- Logging.level_name(@level)
57
- end
58
-
59
- def to_h
60
- {
61
- timestamp: @timestamp.iso8601(Constants::TIMESTAMP_PRECISION),
62
- level: level_name,
63
- component: @component,
64
- message: @message,
65
- context: @context,
66
- thread_id: @thread_id
67
- }
68
- end
69
- end
70
- end
71
- end