I am new to game server design,now assigned to a task to refactory our log server. I create a class Log for communication between Game server and Log server.
class Log
{
public:
void encode(Encoder& encoder) const;
int decode(Decoder& decoder);
private:
std::string sql_cmd;
}
On the game server, there is a class for send log request to log server.
class LogHelper
{
public:
static void LogItemChange(const GameShare::GameItem& item, const PackageChangeDetails& pcd);
{
Log log(get_item_change_sql(item,pcd);
send_to_log_server();
}
private:
static std::string get_item_change_sql(const GameShare::GameItem& item, const PackageChangeDetails& pcd);
}
The question is:
-
Should I generate sql text on game server? If generate sql text on game server, does it have bad effect for performance of game server?
-
If not generate sql text on game server, then should genrate sql text on log server. I should send GameItem and PackageChangeDetails instance data to log server, it will complicated the log server, does anybody has good ided?
If the log’s SQL is generated by the Game Server, then there is almost no need for there to be any Log Server code as it becomes a passthru to the database manager piece, which the Game Server almost certainly already knows about (although I imagine they could potentially be different databases), or could easily interact with.
The Log Server should be a separate component that logs in whatever format is most convenient for you (performance, verbosity, size, etc), and as long as the API is flexible enough, it could be written such that the underlying implementation could be replaced without the Game Server knowing.
By coupling complete knowledge of the underlying implementation with the Game Server code, you not only prevent such a future undertaking, but you are also putting potentially a lot of work into the Game Server’s code that could be done by a separate thread on the Log Server. Not to mention, by opening up the API to SQL, you are putting potential bugs all over the Game Server code that would otherwise be centralized.
The forward looking, replacement-driven approach is ideal when designing Object Oriented systems. If you can avoid coupling to anything except an API, then you can always replace whatever is beneath the API without effecting the outside code (ignoring bugs), but this demands thought being put into the API to ensure that it has enough flexibility for the future.
On that note, I strongly suggest that you implement the Logging API as a pure virtual interface, and then write an implementation on top of it that talks to the database, possibly with a separate implementation that logs to a text file (for convenient, local testing without a database accessible, if that’s ever an issue) as well as a do-nothing implementation. With the first two in mind, it should help to guide you to a better design, and away from coupling.
This also might lead to some basic interface that your other classes implement (e.g.,
public: std::string to_log_string() const;), which can then be used by the Logger to bring in any implementing object and quickly convert it into a logged message.All of this is to say, put the logging related SQL into the Log Server and not in the Game Server. The Game Server shouldn’t care what the Log Server does beyond generically “logging.”