Skip to content

Commit

Permalink
drop tee logger, update Julia dep (#18)
Browse files Browse the repository at this point in the history
- dropping tee logger functionality
- updating Julia dependency to v1.8+
  • Loading branch information
tanmaykm authored Jul 11, 2023
1 parent af9befa commit e8bf2ac
Show file tree
Hide file tree
Showing 5 changed files with 8 additions and 159 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
fail-fast: false
matrix:
version:
- '1.2'
- '1.8'
- '1' # automatically expands to the latest stable 1.x release of Julia
- nightly
os:
Expand Down
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ uuid = "c41e01d8-14e5-11ea-185b-e7eabed7be4b"
keywords = ["log", "rotate", "roller", "logrotate"]
license = "MIT"
authors = ["Tanmay Mohapatra <tanmaykm@gmail.com>"]
version = "0.4.4"
version = "0.5.0"

[compat]
julia = "1.2"
julia = "1.8"
CodecZlib = "0.6,0.7"
JSON = "0.21"

Expand Down
32 changes: 2 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# LogRoller.jl

[![Build Status](https://travis-ci.org/tanmaykm/LogRoller.jl.png)](https://travis-ci.org/tanmaykm/LogRoller.jl)
[![Build Status](https://ci.appveyor.com/api/projects/status/github/tanmaykm/LogRoller.jl?branch=master&svg=true)](https://ci.appveyor.com/project/tanmaykm/logroller-jl/branch/master)
[![Coverage Status](https://coveralls.io/repos/github/tanmaykm/LogRoller.jl/badge.svg?branch=master)](https://coveralls.io/github/tanmaykm/LogRoller.jl?branch=master)
[![Build Status](https://github.com/JuliaLogging/LogRoller.jl/workflows/CI/badge.svg)](https://github.com/JuliaLogging/LogRoller.jl/actions/?query=workflow%3ACI+branch%3Amaster)
[![codecov.io](http://codecov.io/github/JuliaLogging/LogRoller.jl/coverage.svg?branch=main)](http://codecov.io/github/JuliaLogging/LogRoller.jl?branch=main)

Provides:
- `RollingFileWriter` - `IO` implementation to a file writer that rotates files based on file size.
Expand All @@ -28,23 +27,6 @@ Rotates files as below:
- ...
- `<filename>_n.gz` : last rotated file is discarded when rotated


## `RollingFileWriterTee`

Tees raw log entries made a RollingFileWriter on to a Julia `AbstractLogger`.

Each line of text is taken as a single log message.

All log entries are made with the same log level, which can be provided during construction. It leaves
further examination/parsing of log messages (to extract parameters, or detect exact log levels) to the
downstream logger.

Constructor parameters in addition to those for `RollingFileWriter`:
- `logger`: instance of AbstractLogger to tee log entries to
- `assumed_level`: level of the log messages to assume (default Info)

Note: `RollingFileWriterTee` is supported only until Julia 1.7.

## `RollingLogger`

A logger that implements `AbstractLogger` interface and uses a `RollingFileWriter` to provide log rotation.
Expand Down Expand Up @@ -88,16 +70,6 @@ julia> io = RollingFileWriter("/tmp/mylog.log", 1000, 3);
julia> run(pipeline(`myshellscript.sh`; stdout=io, stderr=io));
```

Using `RollingFileWriterTee`

```julia
julia> using LogRoller, Logging

julia> io = RollingFileWriterTee("/tmp/mylog.log", 1000, 3, ConsoleLogger(stderr));

julia> run(pipeline(`myshellscript.sh`; stdout=io, stderr=io));
```

Using `RollingLogger`

```julia
Expand Down
83 changes: 2 additions & 81 deletions src/LogRoller.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import JSON: show_json

import Logging: shouldlog, min_enabled_level, catch_exceptions, handle_message
import Base: write, close, rawhandle
export RollingLogger, RollingFileWriter, RollingFileWriterTee, postrotate
export RollingLogger, RollingFileWriter, postrotate

const BUFFSIZE = 1024*16 # try and read 16K pages when possible
const DEFAULT_MAX_LOG_ENTRY_SIZE = 256*1024
Expand All @@ -34,16 +34,12 @@ mutable struct RollingFileWriter <: IO
filesize::Int
stream::IO
lck::ReentrantLock
procstream::Union{Nothing,Pipe}
procstreamer::Union{Nothing,Task}
procstreamteelogger::Union{Nothing,AbstractLogger}
assumed_level::LogLevel
postrotate::Union{Nothing,Function}

function RollingFileWriter(filename::String, sizelimit::Int, nfiles::Int; rotate_on_init=false)
stream = open(filename, "a")
filesize = stat(stream).size
io = new(filename, sizelimit, nfiles, filesize, stream, ReentrantLock(), nothing, nothing, nothing, Logging.Info, nothing)
io = new(filename, sizelimit, nfiles, filesize, stream, ReentrantLock(), nothing)
if rotate_on_init && filesize > 0
rotate_file(io)
end
Expand All @@ -61,28 +57,11 @@ function postrotate(fn::Function, io::RollingFileWriter)
nothing
end

"""
Tee all lines to the provided logger
"""
function tee(io::RollingFileWriter, logger::AbstractLogger, level::LogLevel)
io.procstreamteelogger = logger
io.assumed_level = level
io
end

"""
Close any open file handle and streams.
A closed object must not be used again.
"""
function close(io::RollingFileWriter)
if io.procstream !== nothing
close(io.procstream)
lock(io.lck) do
io.procstream = nothing
io.procstreamer = nothing
io.procstreamteelogger = nothing
end
end
close(io.stream)
end

Expand Down Expand Up @@ -155,24 +134,6 @@ function rotate_file(io::RollingFileWriter)
nothing
end

"""
Tees raw log entries made a RollingFileWriter on to a provided Julia AbstractLogger.
Each line of text is taken as a single log message.
All log entries are made with the same log level, which can be provided during construction. It leaves
further examination/parsing of log messages (to extract parameters, or detect exact log levels) to the
downstream logger.
"""
function RollingFileWriterTee(filename::String, sizelimit::Int, nfiles::Int, logger::AbstractLogger, assumed_level::LogLevel=Logging.Info)
io = RollingFileWriter(filename, sizelimit, nfiles)
RollingFileWriterTee(io, logger, assumed_level)
end

function RollingFileWriterTee(io::RollingFileWriter, logger::AbstractLogger, assumed_level::LogLevel=Logging.Info)
tee(io, logger, assumed_level)
end

"""
RollingLogger(filename, sizelimit, nfiles, min_level=Info; timestamp_identifier::Symbol=:time, format::Symbol=:console)
Log into a log file. Rotate log file based on file size. Compress rotated logs.
Expand Down Expand Up @@ -277,44 +238,4 @@ function handle_message(logger::RollingLogger, level, message, _module, group, i
nothing
end

function stream_process_logs(writer::RollingFileWriter)
try
while true
logline = readline(writer.procstream; keep=true)
if !isempty(logline)
write(writer, logline)
if writer.procstreamteelogger !== nothing
@logmsg(writer.assumed_level, strip(logline))
end
end
eof(writer.procstream) && break
end
finally
close(writer.procstream)
lock(writer.lck) do
writer.procstream = nothing
writer.procstreamer = nothing
end
end
end

function rawhandle(writer::RollingFileWriter)
lock(writer.lck) do
if (writer.procstream === nothing) || !isopen(Base.pipe_writer(writer.procstream))
writer.procstream = Pipe()
Base.link_pipe!(writer.procstream)
writer.procstreamer = @async begin
if writer.procstreamteelogger !== nothing
with_logger(writer.procstreamteelogger) do
stream_process_logs(writer)
end
else
stream_process_logs(writer)
end
end
end
return rawhandle(Base.pipe_writer(writer.procstream))
end
end

end # module
46 changes: 1 addition & 45 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,35 +73,6 @@ function test_filewriter()
end
end

function test_pipelined_tee()
mktempdir() do logdir
filename1 = "test1.log"
filename2 = "test2.log"
filepath1 = joinpath(logdir, filename1)
filepath2 = joinpath(logdir, filename2)
@test !isfile(filepath1)
@test !isfile(filepath2)

logger1io = open(filepath1, "w+")
logger1 = SimpleLogger(logger1io)
logger2 = RollingFileWriterTee(filepath2, 1000, 3, logger1, Logging.Info)

julia = joinpath(Sys.BINDIR, "julia")
cmd = pipeline(`$julia -e 'for i in 1:5 println(string("hello",i)) end; flush(stdout)'`; stdout=logger2, stderr=logger2)
run(cmd)

close(logger2)
close(logger1io)

@test isfile(filepath1)
@test isfile(filepath2)
@test (2*length(readlines(filepath2))) == length(readlines(filepath1)) # Julia logger entry will be two lines for every raw message
if !Sys.iswindows() # streams do not seem to be flushed cleanly on Windows
@test length(readlines(filepath2)) == 5
end
end
end

function test_logger()
mktempdir() do logdir
filename = "test.log"
Expand Down Expand Up @@ -192,16 +163,7 @@ function test_process_streams()
@test isfile(rolledfile(filepath, 1))
@test !isfile(rolledfile(filepath, 2))

if VERSION < v"1.8"
# pipelined processes are handled differently in Julia 1.8 and later
@test io.procstream !== nothing
@test io.procstreamer !== nothing
@test !istaskdone(io.procstreamer)
end

close(io)
@test io.procstream === nothing
@test io.procstreamer === nothing
end
end

Expand Down Expand Up @@ -479,16 +441,10 @@ end
test_filewriter()
end

if VERSION < v"1.8"
# pipelined tee logger is available only on Julia 1.7 and earlier
@testset "pipelined tee" begin
test_pipelined_tee()
end
end

@testset "process streams" begin
test_process_streams()
end

@testset "logger" begin
test_logger()
test_timestamp_handling()
Expand Down

2 comments on commit e8bf2ac

@tanmaykm
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/87237

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.5.0 -m "<description of version>" e8bf2ac6d8e49328ab3a248ec3bb57a8bfbfcec0
git push origin v0.5.0

Please sign in to comment.