You should consider leveraging Log - Crystal 1.11.2 vs trying to do what you’re wanting to do. Alternatively, it may be easier to use some other external tool that writes all STDOUT output from your program to a file. Tho how to best do this would depend on how you run your binary.
My binary is run from bash, because it’s a command line program.
The purpose is, when my program run a list of tasks (basically a generated crystal script), I want at some point in that script to write into log file. But as I said at some points. Because I need really to split the output in different files
Calling the top-level ::puts always goes through STDOUT, there is no way to reassign the stream used there. You probably need to do logWriter.puts ... instead
So after your answers, I am considering to implement a way to write log.
I am doing a test class to after try to implement that under my project.
I tried that code, but I have 2 problems. The first generated file called log1 is empty, instead of the log2.
And I would like buy default to don’t need to open a file directly.
This class will give you an idea of what I want to do:
class Testy
def initialize
#I WOULD LIKE A WAY BY DEFAULT LOGFILE DONT NEED TO OPEN FILE
@logFilePath = "empty"
@logFile = File.open(@logFilePath,"w")
@logWriter = IO::MultiWriter.new(@logFile)
end
def writeLog(text : String)
@logWriter.puts text
end
def updateLogPath(path : String)
@logFilePath = path
@logFile = File.open(@logFilePath,"w")
@logWriter = IO::MultiWriter.new(@logFile)
end
def start
#THIS GENERATED FILE IS EMPTY
updateLogPath("log1")
writeLog("text1")
updateLogPath("log2")
writeLog("other text")
@logFile.close
end
end
var = Testy.new
var.start
I’m answering on my phone so I could be wrong, but from a quick look I don’t think the first file is closed. It would be better to open and close the file every time you change the file path, or if you switch files frequently, leave it open and close it all together at the end. I also think maybe using flush would fix it.
zohran@alienware-m17-r3 ~/Documents/ISM $ crystal build Main.cr -o ism
Showing last frame. Use --error-trace for full trace.
In ISM/CommandLine.cr:1450:25
1450 | logFile.close
^----
Error: undefined method 'close' for Nil (compile-time type is (File | Nil))
Did you mean 'clone'?
I decided to open in all case a log file anyway, because it’s not a problem if it generate just an empty log, this file will be generated most of the time so …
def runTasksFile(logEnabled = false)
makeLogDirectory("#{@settings.rootPath}#{ISM::Default::Path::LogsDirectory}")
logFile = File.open("#{@settings.rootPath}#{ISM::Default::Path::LogsDirectory}#{ISM::Default::Filename::MainLog}","w")
if logEnabled
logWriter = IO::MultiWriter.new(STDOUT,logFile)
else
logWriter = Process::Redirect::Inherit
end
process = Process.run( "./#{ISM::Default::Filename::Task}",
output: logWriter,
error: logWriter,
shell: true,
chdir: "#{@settings.rootPath}#{ISM::Default::Path::RuntimeDataDirectory}")
logFile.close
if !process.success?
exitProgram
end
end
But now I have a new problem. I did a method to get that file content when I want and to move the content to an other file, and then clear the content.
But look like it don’t work properly. It split just the first time, and not all of the file:
So basically I have a crazy question, if I have already a File.write running in my program, is it still possible from another crystal script at the same time to open the same file and erase a part of the file, but still the first call continue to write inside?
An other question in case it’s not possible (or maybe a bad idea) :
Is it possible when I use the MultiWriter to redirect the output in a string format and store it in a variable?(and then I can parse it)