Hello people!
First of all, some info:
If I can say what structure Zeos is build on, I'll show this:
Code: Select all
component
------------------
dbc
------------------
parsesql - plain
------------------
core
The
Core package have procudures, types and definitions that are common to all others. Common functions, basic types and other "core" stuff.
ParseSQL and Plain work together.
Plain package have all low level, platform specific stuff. This is the interface where client library is made.
ParseSQL is almost the same thing, but it does the platform specific SQL parsing. That package does the SQL text that will be sent to server, and check your SQL to catch errors.
Dbc layer is the second in the top. I may call it the most important package. This is where Plain meets ParseSQL and the functions of Core are used. It join all lower packages into one "API".
Component is the top-most layer, responsable to talk with IDE specific things. It does the "middle-man-work" between user IDE and Dbc API. This is where all components are defined, and this is the layer that you talk with.
If I'm wrong, please, let me know it.
Today, the log is created usgin two procedures,
LogMessage and
LogError. The parameters of procedures are almost equal. As LogMessage redirects for LogError with ErrorCode (integer) = 0 and Error (String) = EmptyString, it don't have this two parameters. The others, common to both proceudres, are:
Category: TZLoggingCategory; A Category for the "Log Packet". TZLogginCategory have this options: lcConnect, lcDisconnect, lcTransaction, lcExecute, lcOther.
Protocol: String; The name of protocol used to generate this Log Packet. It's the same same that apeear into ZConnection protocol field, like 'firebird-1.5' or 'mysql-4.1'.
Msg: string; A message for the Log Packet. It changes much to where the log is generated. Can be a full SQL script or just a few words, explaining whats going on.
Joining all, you'll have the type called
TZLoggingEvent, which is passed to SQLMonitor .
The logging subsystem is all into the Dbc layer. Outside, there's only SQLMonitor, that receives Log Packets from DriverManager, and object located into ZDbcIntfs.pas.
The LogError procedure:
Code: Select all
procedure TZDriverManager.LogError(Category: TZLoggingCategory; const Protocol: string; const Msg: string; ErrorCode: Integer; const Error: string);
var
I: Integer;
Listener: IZLoggingListener;
Event: TZLoggingEvent;
begin
if FLoggingListeners.Count = 0 then
exit;
Event := TZLoggingEvent.Create(Category, Protocol, Msg, ErrorCode, Error);
try
for I := 0 to FLoggingListeners.Count - 1 do
begin
Listener := FLoggingListeners[I] as IZLoggingListener;
try
Listener.LogEvent(Event);
except
end;
end;
finally
Event.Destroy;
end;
end;
As you may see, it loops through all FLoggingListeners and send them the just-created Log Packet (TZLoggingEvent). That behavior permits SQLMonitor to receive log form *anywhere*, as Dbc layer is always the same, independent from Component layer.
Then, I've started the job, but there's a little problems on the way:
1st Problem: Standard Coding ?
I've never get that deep into zeos code. The first thing I've seen: LOTS of differences beween loging calls. Take by example LogError, it's commony called by CheckMyProtocolError, into ZMyProtocolUtils.pas,
only. This is true for DbLib, Interbase, Oracle and SQLite units. A problem is that in DbLib, CheckMyProtocolError is defined as a procudure from TZDBLibConnection and in all other protocols it's a "solitary proceudre".
For MySql and PostgreSQL, there's a call for LogError into ZMyProtocolConnection.Open! And they're allways called! It supposed to be a LogMessage call, not LogError.
In ASA subsystem, there are four calls to LogError, Two in Open/Close of TZASAConnection object, one in CheckASAError and one in TZASASQLDA.CreateException (!).
Even worse is ADO. There are nine calls to LogError, from different places, and no "ADOCheckError".
It's worse becouse you cant say that there's a standard coding template for Dbc layer. Most of them are standard, but some aren't. So, it's difficult to say what data will be avaliable to Log, as the log is invoked from different places, into different protocols. LogMessage has the same problem, but much more worse, as it have much more calls than LogError.
2nd Problem: What data to pass? Can I do a "Cross-Layer" parameter?
My original idea is to change the LogError and LogMessage procedure to be different things. Both will reach SQLMonitor, but with different data. LogError is aways "main called" from CheckMyProtocolError, a place that you don't have much information. LogMessage is called from many places, and you have different information, relative to the place you're calling. A problem: What information to Log ? There goes one idea:
procedure TZDriverManager.LogMessage(Category: TZLoggingCategory;
Driver: IZDriver; Connection: IZConnection; const Msg: string);
Leave LogError as now, and alter LogMessage to include Driver and Connection. These variables are mostly avaliable when LogMessage is called, one or other places they're not, but it can be fixed. But here's another problem: Passing them as parameters will be legal? I know that Zeos is based on JDBC (some commentaries still mention this), and JDBC, as the most Java projects is very problematic with this "OO stuff". It may (will) work well, but I dunno if it's "legal".
3rd Problem: Why not redo all?
Well, thats the end. After this all, my final idea: Rebuild the "log subsystem", change LogError and LogMessage to be the same thing (they're different things, from different places, that end up into the same place (SQLMonitor)), change all that stuff to make it "standard", or the closest of it. I can do this, no problemo. But I need two answers:
Can I do that deep changes?
What data may reach SQLMonitor?
For the second question: On errors, is not possible to pass many details, as they don't exist where LogError is called. It's possible to have a special key with TZLoggingEvent, saying that it's an error or not, and enhance it to have new fields, like the ones present in IZDriver and IZConnection. But, it's NOT currently possible to say from what TZConnection it belongs. We may pass the entire IZConnection for TZLoggingEvent, and them compare with the IZConnection acessible through TZConnection, but there's the "OO conformance" hole again.
Well, I'm on wait of comments.