www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - object.Exception std/stdio.d(1321): Enforcement failed - I must be

reply "Colin Grogan" <grogan.colin gmail.com> writes:
Hi all,

I've done this a million times (I thought!) but I'm getting a 
strange error I cant figure out.

The code:

void writeMsg(string msg){
       logFile.writeln(msg);
}

is failing with this error:

object.Exception std/stdio.d(1321): Enforcement failed
----------------
./tester(pure  safe bool 
std.exception.enforce!(bool).enforce(bool, lazy const(char)[], 
immutable(char)[], ulong)+0x6b) [0x49a343]
./tester(ref std.stdio.File.LockingTextWriter 
std.stdio.File.LockingTextWriter.__ctor(ref std.stdio.File)+0x59) 
[0x4ce019]
./tester( property std.stdio.File.LockingTextWriter 
std.stdio.File.lockingTextWriter()+0x29) [0x4ce179]
./tester(void std.stdio.File.write!(immutable(char)[], 
char).write(immutable(char)[], char)+0x69) [0x49b931]
./tester(void 
std.stdio.File.writeln!(immutable(char)[]).writeln(immutable(char)[])+0x67) 
[0x49b8bf]
./tester(void utils.log.Logger.writeMsg(immutable(char)[])+0x29) 
[0x494631]
./tester(void utils.log.Logger.log(utils.log.LogLevel, 
immutable(char)[])+0xa5) [0x4946dd]
./tester(void utils.log.Logger.logDebug(immutable(char)[])+0xa2) 
[0x49455a]
./tester(_Dmain+0x52) [0x4a3862]
./tester(extern (C) int rt.dmain2._d_run_main(int, char**, extern 
(C) int function(char[][])*).void runMain()+0x18) [0x4bf79c]
./tester(extern (C) int rt.dmain2._d_run_main(int, char**, extern 
(C) int function(char[][])*).void tryExec(scope void 
delegate())+0x2a) [0x4bf2ce]
./tester(extern (C) int rt.dmain2._d_run_main(int, char**, extern 
(C) int function(char[][])*).void runAll()+0x40) [0x4bf7ec]
./tester(extern (C) int rt.dmain2._d_run_main(int, char**, extern 
(C) int function(char[][])*).void tryExec(scope void 
delegate())+0x2a) [0x4bf2ce]
./tester(_d_run_main+0x1ae) [0x4bf28a]
./tester(main+0x17) [0x4bf0d7]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) 
[0x7f6bcc3f176d]


Also, I'm creating the logFile variable as follows:
File logFile = File(fileName, "w");

If ye need the code around it I'll be glad to post it, but the 
logFile.writeln(msg) is the specific line it breaks on. If I 
comment that out all is good.
It writes to the file once, and next time I call the function it 
fails.

My guess is the lock on the file isn't releasing after the first 
write?
Aug 15 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/15/2013 10:03 AM, Colin Grogan wrote:

 I've done this a million times (I thought!) but I'm getting a strange
 error I cant figure out.

 The code:

 void writeMsg(string msg){
        logFile.writeln(msg);
What is logFile?
 }

 is failing with this error:

 object.Exception std/stdio.d(1321): Enforcement failed
 ----------------
 ./tester(pure  safe bool std.exception.enforce!(bool).enforce(bool, lazy
 const(char)[], immutable(char)[], ulong)+0x6b) [0x49a343]
 ./tester(ref std.stdio.File.LockingTextWriter
 std.stdio.File.LockingTextWriter.__ctor(ref std.stdio.File)+0x59)
 [0x4ce019]
...
 Also, I'm creating the logFile variable as follows:
 File logFile = File(fileName, "w");
That looks like a local variable. How does writeMsg see it?
 If ye need the code around it I'll be glad to post it
It is very helpful if you can reproduce it in a minimal example. The following program works with v2.064-devel-52cc287: import std.stdio; enum fileName = "deneme.txt"; File logFile; static this() { logFile = File(fileName, "w"); } void writeMsg(string msg){ logFile.writeln(msg); } void main() { writeMsg("hello"); writeMsg("world"); } Can you add to it and see when the problem appears. Ali
Aug 15 2013
parent reply "Colin Grogan" <grogan.colin gmail.com> writes:
Hi Ali,

Heres my full Logger class.

module utils.log;

import std.stdio;
import std.string;
import std.datetime;
public enum LogLevel {Fatal=0, Severe=1, Info=2, Debug=3, 
Verbose=4};

public class Logger{
     public:

     this(LogLevel minLevel = LogLevel.Info, string 
fileName="logfile.log"){
         this.minLevel = minLevel;
         logFile = File(fileName, "w");
         this.writeMsg(format("Opened file for writing at [%s]", 
currTimestamp()));
         logFile.flush();
         scope(exit){
             logInfo("End log");
             logFile.close();
         }
     }
     void logFatal(string message){
         this.log(LogLevel.Fatal, "FATAL - " ~ message);
     }
     void logSevere(string message){
         this.log(LogLevel.Severe, "SEVERE - " ~ message);
     }
     void logInfo(string message){
         this.log(LogLevel.Info, format("INFO - %s",message));
     }
     void logDebug(string message){
         this.log(LogLevel.Debug, "DEBUG - " ~ message);
     }
     void logVerbose(string message){
         this.log(LogLevel.Verbose, "VERBOSE - " ~ message);
     }

     private:
     void writeMsg(string msg){
         logFile.writeln(msg);
     }
     void log(LogLevel level, string message){
         if(this.minLevel <= level){
             writefln("Before write! %s",message);
             string timestamp = currTimestamp();
             this.writeMsg(format("[%s] %s", timestamp, message));
             writefln("After write! %s", message);
             logFile.flush();
         }
     }
     string currTimestamp(){
         auto currTime = Clock.currTime();
         return currTime.toISOExtString()[0..$-8];
     }

     private:
         LogLevel minLevel;
         File logFile;
}

logFile is a class variable, so its definatly visible.
Ill go with adding to your code now and see at what point it 
breaks.

Thanks!

On Thursday, 15 August 2013 at 17:33:11 UTC, Ali Çehreli wrote:
 On 08/15/2013 10:03 AM, Colin Grogan wrote:

 I've done this a million times (I thought!) but I'm getting a
strange
 error I cant figure out.

 The code:

 void writeMsg(string msg){
        logFile.writeln(msg);
What is logFile?
 }

 is failing with this error:

 object.Exception std/stdio.d(1321): Enforcement failed
 ----------------
 ./tester(pure  safe bool
std.exception.enforce!(bool).enforce(bool, lazy
 const(char)[], immutable(char)[], ulong)+0x6b) [0x49a343]
 ./tester(ref std.stdio.File.LockingTextWriter
 std.stdio.File.LockingTextWriter.__ctor(ref
std.stdio.File)+0x59)
 [0x4ce019]
...
 Also, I'm creating the logFile variable as follows:
 File logFile = File(fileName, "w");
That looks like a local variable. How does writeMsg see it?
 If ye need the code around it I'll be glad to post it
It is very helpful if you can reproduce it in a minimal example. The following program works with v2.064-devel-52cc287: import std.stdio; enum fileName = "deneme.txt"; File logFile; static this() { logFile = File(fileName, "w"); } void writeMsg(string msg){ logFile.writeln(msg); } void main() { writeMsg("hello"); writeMsg("world"); } Can you add to it and see when the problem appears. Ali
Aug 15 2013
next sibling parent "Colin Grogan" <grogan.colin gmail.com> writes:
I should have put this here too:

My main function.
import std.stdio;
import utils.log;
void main()
{
     Logger log = new Logger(LogLevel.Info, "somefile.log");
     log.logDebug("Test");
}

When creating the log file, it prints the text in the constructor 
as expected, but the call to log.logDebug() fails. This is why 
I'm thinking its locking but not releasing?


On Thursday, 15 August 2013 at 17:41:00 UTC, Colin Grogan wrote:
 Hi Ali,

 Heres my full Logger class.

 module utils.log;

 import std.stdio;
 import std.string;
 import std.datetime;
 public enum LogLevel {Fatal=0, Severe=1, Info=2, Debug=3, 
 Verbose=4};

 public class Logger{
     public:

     this(LogLevel minLevel = LogLevel.Info, string 
 fileName="logfile.log"){
         this.minLevel = minLevel;
         logFile = File(fileName, "w");
         this.writeMsg(format("Opened file for writing at [%s]", 
 currTimestamp()));
         logFile.flush();
         scope(exit){
             logInfo("End log");
             logFile.close();
         }
     }
     void logFatal(string message){
         this.log(LogLevel.Fatal, "FATAL - " ~ message);
     }
     void logSevere(string message){
         this.log(LogLevel.Severe, "SEVERE - " ~ message);
     }
     void logInfo(string message){
         this.log(LogLevel.Info, format("INFO - %s",message));
     }
     void logDebug(string message){
         this.log(LogLevel.Debug, "DEBUG - " ~ message);
     }
     void logVerbose(string message){
         this.log(LogLevel.Verbose, "VERBOSE - " ~ message);
     }

     private:
     void writeMsg(string msg){
         logFile.writeln(msg);
     }
     void log(LogLevel level, string message){
         if(this.minLevel <= level){
             writefln("Before write! %s",message);
             string timestamp = currTimestamp();
             this.writeMsg(format("[%s] %s", timestamp, 
 message));
             writefln("After write! %s", message);
             logFile.flush();
         }
     }
     string currTimestamp(){
         auto currTime = Clock.currTime();
         return currTime.toISOExtString()[0..$-8];
     }

     private:
         LogLevel minLevel;
         File logFile;
 }

 logFile is a class variable, so its definatly visible.
 Ill go with adding to your code now and see at what point it 
 breaks.

 Thanks!

 On Thursday, 15 August 2013 at 17:33:11 UTC, Ali Çehreli wrote:
 On 08/15/2013 10:03 AM, Colin Grogan wrote:

 I've done this a million times (I thought!) but I'm getting a
strange
 error I cant figure out.

 The code:

 void writeMsg(string msg){
       logFile.writeln(msg);
What is logFile?
 }

 is failing with this error:

 object.Exception std/stdio.d(1321): Enforcement failed
 ----------------
 ./tester(pure  safe bool
std.exception.enforce!(bool).enforce(bool, lazy
 const(char)[], immutable(char)[], ulong)+0x6b) [0x49a343]
 ./tester(ref std.stdio.File.LockingTextWriter
 std.stdio.File.LockingTextWriter.__ctor(ref
std.stdio.File)+0x59)
 [0x4ce019]
...
 Also, I'm creating the logFile variable as follows:
 File logFile = File(fileName, "w");
That looks like a local variable. How does writeMsg see it?
 If ye need the code around it I'll be glad to post it
It is very helpful if you can reproduce it in a minimal example. The following program works with v2.064-devel-52cc287: import std.stdio; enum fileName = "deneme.txt"; File logFile; static this() { logFile = File(fileName, "w"); } void writeMsg(string msg){ logFile.writeln(msg); } void main() { writeMsg("hello"); writeMsg("world"); } Can you add to it and see when the problem appears. Ali
Aug 15 2013
prev sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 15 August 2013 at 17:41:00 UTC, Colin Grogan wrote:
     this(LogLevel minLevel = LogLevel.Info, string 
 fileName="logfile.log")
     {
         this.minLevel = minLevel;
         logFile = File(fileName, "w");
         this.writeMsg(format("Opened file for writing at [%s]", 
 currTimestamp()));
         logFile.flush();
         scope(exit){
             logInfo("End log");
             logFile.close();
         }
     }
This "scope(exit)" runs when you exit the scope, eg: the _constructor_, not when your log is destroyed. YOur constructor is basically leaving your log file in a closed state, making it useless. Instead, use a destroyer: ~this() { logInfo("End log"); logFile.close(); } Note though that this will not *actually* work, because since the destroyer is run during a collection run, you can't allocate, and logInfo calls format, which allocates. As a matter of fact, you should avoid calling format at all. Instead, your "writeMsg" should look like this void writeMsg(Args...)(string fmt, Args args){ logFile.writefln(fmt, args); } Then, in your log, instead of doing: this.writeMsg(format("[%s] %s", timestamp, message)); simply do: this.writeMsg("[%s] %s", timestamp, message); This doesn't fix everything though, and you should also rework your "logLevel" functions to not allocate: For example, by making "log" accept two strings.
Aug 15 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 15 August 2013 at 18:09:21 UTC, monarch_dodra wrote:
 This doesn't fix everything though, and you should also rework 
 your "logLevel" functions to not allocate: For example, by 
 making "log" accept two strings.
Another issue is that printing a time will always allocate a string, so there is (currently) no way to log at what time the log file is closed, if you rely on the destructor.
Aug 15 2013
parent "Colin Grogan" <grogan.colin gmail.com> writes:
I've decided whats the point in printing a time that the file 
closed at, the last message will probably tell me that anyway if 
theres an error to find.

Your suggestions worked perfectly, I've obviously a lot to learn 
on how to use the intricacies of D.

Thanks very much!

On Thursday, 15 August 2013 at 19:54:42 UTC, monarch_dodra wrote:
 On Thursday, 15 August 2013 at 18:09:21 UTC, monarch_dodra 
 wrote:
 This doesn't fix everything though, and you should also rework 
 your "logLevel" functions to not allocate: For example, by 
 making "log" accept two strings.
Another issue is that printing a time will always allocate a string, so there is (currently) no way to log at what time the log file is closed, if you rely on the destructor.
Aug 15 2013