Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 151e4e74cf | |||
| 42b66366ae | |||
| b0761fae75 | |||
| f9e952e5ed | |||
| 397885511a | |||
| ee8ade1189 | |||
| 20c51cf39f | |||
| f09a53b6c3 | |||
| c078948a7c | |||
| 3780eb41df | |||
| c28b7ebf84 | |||
| 27fd52fa71 |
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
name = "GeneralUtils"
|
name = "GeneralUtils"
|
||||||
uuid = "c6c72f09-b708-4ac8-ac7c-2084d70108fe"
|
uuid = "c6c72f09-b708-4ac8-ac7c-2084d70108fe"
|
||||||
version = "0.6.2"
|
version = "0.6.9"
|
||||||
authors = ["tonaerospace <tonaerospace.etc@gmail.com>"]
|
authors = ["tonaerospace <tonaerospace.etc@gmail.com>"]
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|||||||
+5
-5
@@ -46,13 +46,13 @@ https://s3-web.mydomain.com/my_bucket_name/users-1005.json
|
|||||||
# 1. Custom GarageConfig Definition (Thread-Safe, No Global State)
|
# 1. Custom GarageConfig Definition (Thread-Safe, No Global State)
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
|
|
||||||
struct SimpleCredentials
|
mutable struct SimpleCredentials
|
||||||
access_key_id::String
|
access_key_id::String
|
||||||
secret_key::String
|
secret_key::String
|
||||||
token::String
|
token::String
|
||||||
end
|
end
|
||||||
|
|
||||||
struct GarageConfig <: AWS.AbstractAWSConfig
|
mutable struct GarageConfig <: AWS.AbstractAWSConfig
|
||||||
endpoint::String
|
endpoint::String
|
||||||
region::String
|
region::String
|
||||||
credentials::SimpleCredentials
|
credentials::SimpleCredentials
|
||||||
@@ -113,7 +113,7 @@ julia> storage = GarageStorage("https://s3-api.yiem.cc", "GKb08015", "55114ff948
|
|||||||
GarageStorage(GarageConfig(...), "sommpanion-s3")
|
GarageStorage(GarageConfig(...), "sommpanion-s3")
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
struct GarageStorage
|
mutable struct GarageStorage
|
||||||
config::GarageConfig
|
config::GarageConfig
|
||||||
bucket::String
|
bucket::String
|
||||||
end
|
end
|
||||||
@@ -146,7 +146,7 @@ julia> downloadUrl.web
|
|||||||
"https://s3-web.yiem.cc/sommpanion-s3/test.json"
|
"https://s3-web.yiem.cc/sommpanion-s3/test.json"
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
struct put_file
|
mutable struct put_file
|
||||||
storage::GarageStorage
|
storage::GarageStorage
|
||||||
end
|
end
|
||||||
function (pf::put_file)(key::String, data::Union{String, Vector{UInt8}}
|
function (pf::put_file)(key::String, data::Union{String, Vector{UInt8}}
|
||||||
@@ -279,7 +279,7 @@ end
|
|||||||
- `enabled::Bool`: Whether the rule is active (default: `true`).
|
- `enabled::Bool`: Whether the rule is active (default: `true`).
|
||||||
- `id::String`: Unique identifier for the rule (default: auto-generated).
|
- `id::String`: Unique identifier for the rule (default: auto-generated).
|
||||||
"""
|
"""
|
||||||
struct LifecycleExpiration
|
mutable struct LifecycleExpiration
|
||||||
prefix::String
|
prefix::String
|
||||||
days::Int
|
days::Int
|
||||||
enabled::Bool
|
enabled::Bool
|
||||||
|
|||||||
+102
-2
@@ -4,12 +4,12 @@ export timedifference, showstracktrace, findHighestIndexKey, uuid4snakecase, rep
|
|||||||
findMatchingDictKey, randstring, randstrings, timeout,
|
findMatchingDictKey, randstring, randstrings, timeout,
|
||||||
dataframeToCSV, dfToVectorDict, disintegrate_vectorDict, getDataFrameValue, dfRowtoString,
|
dataframeToCSV, dfToVectorDict, disintegrate_vectorDict, getDataFrameValue, dfRowtoString,
|
||||||
dfToString, dataframe_to_json_list, dictToString, dictToString_noKey, issomething,
|
dfToString, dataframe_to_json_list, dictToString, dictToString_noKey, issomething,
|
||||||
dictToString_numbering, extract_triple_backtick_text,
|
dictToString_numbering, extract_triple_backtick_text, eventSink,
|
||||||
countGivenWords, remove_french_accents, removestring,
|
countGivenWords, remove_french_accents, removestring,
|
||||||
extractTextBetweenCharacter, extractTextBetweenString,
|
extractTextBetweenCharacter, extractTextBetweenString,
|
||||||
convertCamelSnakeKebabCase, fitrange, recentElementsIndex, nonRecentElementsIndex
|
convertCamelSnakeKebabCase, fitrange, recentElementsIndex, nonRecentElementsIndex
|
||||||
|
|
||||||
using JSON, DataStructures, Distributions, Random, Dates, UUIDs, DataFrames
|
using JSON, DataStructures, Distributions, Random, Dates, UUIDs, DataFrames, NATS, Dates
|
||||||
|
|
||||||
# ---------------------------------------------- 100 --------------------------------------------- #
|
# ---------------------------------------------- 100 --------------------------------------------- #
|
||||||
|
|
||||||
@@ -1173,6 +1173,106 @@ function removestring(text::String, removelist::Vector{String})::String
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
Create an event sink for logging messages and/or publishing to NATS or printing to console. File logging defaults to false.
|
||||||
|
|
||||||
|
# Fields
|
||||||
|
- `natsConn`: NATS connection, or `nothing` for file-only sink
|
||||||
|
- `topic`: NATS topic to publish to, or `nothing` for file-only sink
|
||||||
|
- `service_name`: Optional prefix added to log entries
|
||||||
|
- `log_file`: Path to the log file
|
||||||
|
- `max_log_entries`: Maximum number of entries to keep in the log file
|
||||||
|
|
||||||
|
# Callable interface
|
||||||
|
```julia
|
||||||
|
(es::eventSink)(msg::String; log=false, publish=true, console=true) -> Nothing
|
||||||
|
```
|
||||||
|
|
||||||
|
Three independent outputs — each defaults to `true` except `log`:
|
||||||
|
- `console` (default `true`) → println to stdout
|
||||||
|
- `publish` (default `true`) → publish to NATS topic (no-op if no connection)
|
||||||
|
- `log` (default `false`) → append to `log_file`
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
```julia
|
||||||
|
using NATS, Dates
|
||||||
|
|
||||||
|
conn = NATS.connect("nats.yiem.cc")
|
||||||
|
|
||||||
|
# ——— With NATS (console + NATS by default) ———
|
||||||
|
es = eventSink(natsConn=conn, topic="agent.events", service_name="agent1")
|
||||||
|
es("starting up") # console + NATS
|
||||||
|
es("logged"; log=true) # console + file + NATS
|
||||||
|
es("quiet"; console=false) # NATS only
|
||||||
|
es("file+nats"; log=true, console=false) # file + NATS
|
||||||
|
es("console-only"; publish=false, log=false) # console only
|
||||||
|
|
||||||
|
# ——— File-only sink (no NATS connection) ———
|
||||||
|
es2 = eventSink(log_file="./log/eventSink2.md", service_name="worker")
|
||||||
|
es2("ready") # console only
|
||||||
|
es2("file-logged"; log=true) # console + file
|
||||||
|
es2("file-only"; log=true, console=false) # file only
|
||||||
|
es2("silent"; console=false) # nothing (no NATS, log=false, console=false)
|
||||||
|
|
||||||
|
NATS.drain(conn)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
struct eventSink
|
||||||
|
natsConn::Union{NATS.Connection, Nothing}
|
||||||
|
topic::Union{String, Nothing}
|
||||||
|
service_name::String
|
||||||
|
log_file::String
|
||||||
|
max_log_entries::Int
|
||||||
|
end
|
||||||
|
eventSink(; natsConn=nothing, topic=nothing, service_name="", log_file="./log/eventSink.md", max_log_entries=100) =
|
||||||
|
eventSink(natsConn, topic, service_name, log_file, max_log_entries)
|
||||||
|
function (es::eventSink)(msg::String; log=false, publish=true, console=true)
|
||||||
|
timestamp = Dates.format(now(), "yyyy-mm-ddTHH:MM:SS.sss")
|
||||||
|
svc_prefix = isempty(es.service_name) ? "" : "[$(es.service_name)] "
|
||||||
|
entry = "- [$timestamp] $svc_prefix$msg\n"
|
||||||
|
if console
|
||||||
|
println("[$timestamp] $svc_prefix$msg")
|
||||||
|
end
|
||||||
|
if log
|
||||||
|
log_dir = dirname(es.log_file)
|
||||||
|
mkpath(log_dir)
|
||||||
|
open(es.log_file, "a") do f
|
||||||
|
write(f, entry)
|
||||||
|
end
|
||||||
|
# Rotate after write — keep only last max_log_entries entries
|
||||||
|
content = read(es.log_file, String)
|
||||||
|
entries = split(content, r"- \[", keepempty=false)
|
||||||
|
if length(entries) > es.max_log_entries
|
||||||
|
rotate!(es)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if publish && es.topic !== nothing && es.natsConn !== nothing
|
||||||
|
try
|
||||||
|
NATS.publish(es.natsConn, es.topic, entry)
|
||||||
|
catch e
|
||||||
|
@warn "eventSink NATS publish failed" exception=e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
"""
|
||||||
|
rotate!(es::eventSink) -> Nothing
|
||||||
|
|
||||||
|
Rewrite the log file keeping only the last `max_log_entries` entries.
|
||||||
|
Call after writing when the entry count reaches the limit.
|
||||||
|
"""
|
||||||
|
function rotate!(es::eventSink)
|
||||||
|
content = read(es.log_file, String)
|
||||||
|
entries = split(content, r"- \[", keepempty=false)
|
||||||
|
open(es.log_file, "w") do f
|
||||||
|
write(f, "- [")
|
||||||
|
for e in entries[2:end]
|
||||||
|
write(f, "- [", e)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user