Programming Question Logging: Tricky Task, any idea?

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
104
Points
78
Hi guys,

I'm facing a tricky task coming to the end of the VesselBuilder project.

I am currently working on a Log class which which allows to log all the relevant information. I think it is absolutely a must to have as much information as possible in a log file and the experience with MS2015 just confirms that.

Now, here's the issue: I would like not to use the Orbiter log file since I'd like to have a more customized and dedicated file. I have managed to make all the vessels to write to a same log file, and that's easy, but the issue is that I would like for each simulation run to start from a blank file, but I don't know how to reset the file at each run since the calls to the log file are from vessels, and vessels can be in any number and can come and go at any time during sim... So at the time the log just keeps appending lines, which is a nonsense in the long term...

The wayout I see are just:
- to write a dedicated vessel log for each vessel created but that would be quite cumbersome and I don't like it at all
- to use orbiter log
- to write a simple plugin that resets the log at every sim run but it seems ridicoulus to me to force the users to install another plugin which just does that...

Does anyone have any idea on how I could do it?

Thanks!
Fred
 

Donamy

Addon Developer
Addon Developer
Donator
Beta Tester
Joined
Oct 16, 2007
Messages
6,906
Reaction score
201
Points
138
Location
Cape
Couldn't you have the user add a title, or name for the project ?
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,605
Reaction score
2,327
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
I would just use the first option. Its the only really workable way without compromising what a logging system should be capable of.

Otherwise, you are rather looking at an event stream, which could allow more functions, but is less robust, (slightly) slower and way more complex. Especially when something crashes, it gets annoying.
 

Linguofreak

Well-known member
Joined
May 10, 2008
Messages
5,031
Reaction score
1,271
Points
188
Location
Dallas, TX
It's been a while since I've actually run Orbiter, but does the Orbiter log file contain a timestamp for when Orbiter was started? If it does, when a vessel is initialized, it could check to see if there are any messages in the VesselBuilder log that are more recent than the Orbiter start time. If there aren't any, the vessel knows that it's the first VesselBuilder vessel to be spun up and blanks the VesselBuilder log. If there are messages after the Orbiter start timestamp (or if the log is blank), the vessel knows that it's not the first vessel spun up, or that the log had been blanked outside of Orbiter, so it doesn't need to blank the log. If the log doesn't exist, then either this is the first run of VesselBuilder on this installation, or the log has been deleted by another program, so it needs to be created.

Other than that, you could define a global "log is current" variable that is initialized at compile time to false that each vessel checks when initialized. If the variable is true, the vessel does nothing. If it's false, the vessel blanks the log and sets the variable to true.
 

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,869
Reaction score
2,128
Points
203
Location
between the planets
to write a simple plugin that resets the log at every sim run but it seems ridicoulus to me to force the users to install another plugin which just does that...

So... the vessel builder itself isn't a plugin? I guess I'd need more information on how it is integrated then before I could even think of potential solutions.
 

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
104
Points
78
So... the vessel builder itself isn't a plugin? I guess I'd need more information on how it is integrated then before I could even think of potential solutions.

Nope, it's a vessel module.

It is basically a vessel which parses all its settings from the cfg vessel class file and allows to edit and write them through a dialog window, allowing to start from an empty vessel and arriving to a complete one.

I'm working on the log since many things can go wrong both if I forgot something or if the user does anything in the wrong sequence (like assigning the swap of the touchdown points to an animation and then deleting the animation, or stuff like that).

Thank guys for the suggestions. For the time being I'm just doing one log for each vessel, just because before getting to the final release I'm trying to log a large amount of information. Then, when the system gets stable I will reduce the log information and I will try some options to have a unique file!

:cheers:
 

Linguofreak

Well-known member
Joined
May 10, 2008
Messages
5,031
Reaction score
1,271
Points
188
Location
Dallas, TX
So... the vessel builder itself isn't a plugin? I guess I'd need more information on how it is integrated then before I could even think of potential solutions.

Yeah, that's the other thing I was thinking. My understanding (though I've not touched Orbiter in years or VB at all) is that VB is an Orbiter plugin that displays an in-sim interface for constructing vessels. In that case the plugin itself ought to be able to reset the log file independently of the vessels it administers.
 

kuddel

Donator
Donator
Joined
Apr 1, 2008
Messages
2,064
Reaction score
507
Points
113
As long as every log-task/thread closes the file handle as soon as possible, any other thread/task can do whatever with that file (clear, append, remove some lines...)
 

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
104
Points
78
As long as every log-task/thread closes the file handle as soon as possible, any other thread/task can do whatever with that file (clear, append, remove some lines...)

yep, but that was not an issue, the issue was to know from within a vessel wether to clear the file or not.
 

kuddel

Donator
Donator
Joined
Apr 1, 2008
Messages
2,064
Reaction score
507
Points
113
oops then I have missed the point ;)
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,398
Reaction score
578
Points
153
Location
Vienna
I'd put a common log handler into a startup configuration module, similar to what stock Atlantis and DG provide. This way you have a central module you don't have to activate.

I used this for AU in order to have a common ATC talker handler and it worked quite well.
 

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,869
Reaction score
2,128
Points
203
Location
between the planets
Nope, it's a vessel module.

Of course it would be, silly me...
So what would speak against handling logging in a static member of the vessel class? That could check whether it's a first call or not without issues.
 

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
104
Points
78
So what would speak against handling logging in a static member of the vessel class? That could check whether it's a first call or not without issues.

My ignorance on the matter :lol:

I have zero confidence with global or static class variables, I have to learn how to treat them properly
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,605
Reaction score
2,327
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
I have zero confidence with global or static class variables, I have to learn how to treat them properly


Its not too hard, you just need to remember that they are global between multiple objects - its far easier in Orbiter since it is not multithreaded yet.



And don't do such weird stuff like doing complex calculations in constructors of classes, because you don't know static methods....
 

Linguofreak

Well-known member
Joined
May 10, 2008
Messages
5,031
Reaction score
1,271
Points
188
Location
Dallas, TX
My ignorance on the matter :lol:

I have zero confidence with global or static class variables, I have to learn how to treat them properly

Think of your program as a book of instructions for some desk clerk working with paper and pencil. Each function is a page in the instruction book.

The desk worker has a blank space in the middle of his desk for a pile of sticky notes and a sheet of A4 to his left. He can also remember one value at a time that he does not have written down anywhere.

First we'll consider what local variables look like in this model, as you seem to be fairly comfortable with that.

I learned Object-Oriented programming through Java (and with Java vocabulary rather than C++ vocabulary), and learned C later, but am not really confident with C++ (which is what the Orbiter API uses), so my example code will be with C, but should generalize to C++.

Let's say you call a function defined as:

Code:
int foo(int bar, int baz, int blah)
{
    int n = 0; 
    n = bar + baz + blah;
    return n;
}

One would normally in this case write "return bar + baz + blah;", but I'm being a bit wordier than I have to be in order to make a few points.

Let's say that you call foo() from main like this:

Code:
int main()
{
    /*code*/
    int i = foo (1, 2, 3);
    /*code*/
}

To make the function call, you write the following instructions for the clerk: "Put a new sticky note on the pile, write the label 'go back to:' on the first line of the sticky note, and write the number of this page in the instruction book next to it and the line number of this line. The write the label "return value" on the second line of the sticky note, and leave it blank. The write the labels "bar", "baz", and "blah" on the next available lines on the top sticky note, and write the values 1, 2, and 3, respectively, next to them. Then find foo() in the index, and go to the corresponding page number."

When you declare n (a local variable to foo), you tell the clerk "write the label n on the next available line on the top sticky note."

When you assign bar + baz + blah to n, you tell the clerk:

"Find the values written on the lines on the top sticky note labeled 'bar', 'baz', and 'blah' and add them. Write the result on the line labeled 'n'".

When you return the value of n from the function, you write the instructions: "Remember the value on the line labeled n. Then go to the page number and line number in the instruction book written on the line labeled 'go back to' on the sticky note in your hand, and throw the sticky note in your hand away".

When the desk clerk gets back to "main()", he sees the next instructions are: "label the next available line on the top sticky note 'i', and write the last number you remembered on that line".

So local variables are lines on the top sticky note. When you enter a new function, the clerk covers up the top sticky note with a new one and writes the variables and parameters for the new function on the new sticky note. When you exit a function, he remembers the return value and throws the sticky note away, uncovering the sticky note for the function you're returning to, then writes the return value into whatever variable you're assigning it into (or forgets it if you don't use the return value).

So now we get to global variables and static class variables.

My example code will be with C global variables, but the way I explain it should generalize to C++ static class variables.

Lets say you have the following code:

Code:
const int blah = 3;
int i;
int n = 0;
int main()
{
    foo(1,2);
    foo(2,4);
}
void foo(int bar, int baz)
{
    i = bar + baz + blah;
    n += i;
}

This is like the code we had earlier, but i and n have been moved from being local variables of main and foo to being global variables, and blah been moved from being a parameter of foo to being a global constant. Foo has void return type, because it now assigns into global variables instead of returning a value.

In our desk clerk model, the labels for the global variables (and the class static ones in ) are pre-written in ink on the sheet of A4 paper to the desk clerk's left. The value for i is blank, the value for n is pre-written in pencil, and the value for blah is pre-written in ink.

So now we get to the instruction book. Unlike for the sticky notes, the instructions never tell him to write a label for a line on the A4 sheet, because the labels are pre-printed. And they never tell him to write a value for blah, because that value is pre-printed, so he can't erase it and write a new one. Also, unlike for the sticky notes, he is never told to put another sheet of A4 on top of the current one, or to throw the current one away. The same sheet is always there and ready to use.

The call and return instructions are the same as before (except that he doesn't have to remember a return value for foo()). When we assign to i, the clerk's instructions say "Add the values on the lines labeled 'bar' and 'baz' on the top sticky note, and the line labeled 'blah' on the A4 sheet, and write the result on the line labeled 'i' on the A4 sheet". When we assign to n, the instructions say "Add the value on the line labeled 'i' on the A4 sheet and the line labeled 'n' on the A4 sheet, and write the result in the line labeled 'n' on the A4 sheet."

After the first invocation of foo(), the value of i is 6 and the value of n is 6. After the second invocation, the value of i is 9 and the value of n is 15.

Member variables for an object (in an object oriented language), or an instance of a struct (in plain C) are stored wherever the containing object/struct is stored, either on the sticky notes or on the A4.

So local variables keep state relevant to the execution of a function, global variables keep track of state relevant to the execution of the program as a whole, and member variables keep track of the state of an object, however long it lasts for.

I could also extend the desk clerk model to cover dynamically allocated variables (state that needs to be kept track of for less than the lifetime of the program, but needs to accessible regardless of which sticky note is currently on top of the pile) and pointers, which are variables that tell you where to find other variables (mostly where to find dynamically allocated variables, but sometimes other things), as well as things like calls to external APIs, but that will take a while, and you haven't said that you aren't confident with them.
 

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
104
Points
78
that's a marvellous explanation!!!

:hail::hail::hail:

Thank you very much!!!
 
Top