GDC 2005 - Programmer Joe

Download Report

Transcript GDC 2005 - Programmer Joe

FLogging:
Metric Collection on the High Seas
Joe Ludwig
Director of Development
Flying Lab Software
What is FLogging?
Server-side
 Metric collection
 Game events with parameters
 Server performance events

Formal + Log
=
FLog
Design Goals

Designer goals
Lots of different views on data
 Possible to derive context from data


Programmer goals
Easy to add new flog types
 No global recompiles

Data Collection
Adding a new flog type
Add any new field types in XML
 Add the new flog type in XML
 Upgrade database to generate SQL

Tables
 Procedures
 Views


Add call to record flog
Flog types defined in XML
Flogger_field_types.xml:
<flsFlogFieldType>
<name>level</name>
<sqlType>TINYINT</sqlType>
</flsFlogFieldType>
Flog types defined in XML
Flogger_types.xml:
<flsFlogType>
<name>level_gained</name>
<fieldNames>
<e>level</e>
</fieldNames>
<usesObjectId>true</usesObjectId>
<hideByDefault>false</hideByDefault>
</flsFlogType>
Add call to record flog
void flsAdvancementManager::setLevel(flsCharacter* pCharacter,
igChar iNewLevel)
{
pCharacter->assignNewLevel(iNewLevel);
if(pCharacter->isPlayer())
{
flsFlogger::flogf("level_gained",
pCharacter->getLocalId(),
"%d", iNewLevel);
}
}
Database Format - Tables
Flog table – one entry per flog
 Value tables – One entry per flog that
uses that field type
 Flog_type table – One entry per type

flog table
Field
Type
Id
BIGINT IDENTITY
Flog_type
INT
Flog_time
DATETIME
Cluster_id
INT
Character_id
INT
Puid
BIGINT
value table
Field
Type
Id
BIGINT
Value
TINYINT
Type of value column is controlled by
flogger_field_types.xml
flog_type table
Field
Type
Flog_type
INT
Name
CHAR(32)
hideByDefault
TINYINT
Database Format –
Stored Procedures
Flog type procedures
 Flog type expiration procedures
 Flog_heartbeat procedure

Flog type procedures
CREATE PROCEDURE Flog_level_gained
@iObjectId INT, @level_param TINYINT
AS BEGIN
DECLARE @pid bigint, @cid int;
SELECT @pid = puid, @cid = clusterid FROM #flog_vars;
INSERT INTO flog (puid, cluster_id, flog_type, object_id) VALUES
(@pid, @cid, 3, @iObjectId);
DECLARE @lastid BIGINT;
SET @lastid = SCOPE_IDENTITY();
INSERT INTO flog_level (id, value) VALUES (@lastid, @level_param);
END
Flog age procedures
CREATE PROCEDURE
Flog_Age_skill_used
AS
DELETE flog FROM flog, flog_item_id
WHERE DATEDIFF(DAY, flog.flog_time,
CURRENT_TIMESTAMP)>=2 AND
flog.id=flog_item_id.id
Flog Heartbeat procedure
CREATE PROCEDURE Flog_Maintenance
AS BEGIN
EXEC flog_Age_maneuver_skill_used;
EXEC flog_Age_skill_used;
EXEC flog_Age_volley_fired;
END
Database Format – Type View
CREATE VIEW Flog_Data_level_gained
AS
SELECT flog.id, flog_level.value AS
[level]
FROM flog INNER JOIN flog_level ON
flog.id=flog_level.id
WHERE flog.flog_type=3
What we flog








Login/Logout events
Zoning
Economic events
Advancement events
Missions
Conquest events
Chat
GM commands
How much data?
4.5 million new flog records per week
 Top 5 flog types account for 50%

room_entered
xp_kill
exit_used
money_gained_kill
mission_stage_advanced
money_lost_recipe
18.95%
11.78%
7.66%
6.59%
5.76%
4.20%
Example flog output
Time
Type
7/10/2007
2:59:17
PM
chat_society
message: ahoy Joany
View
Log
7/10/2007
2:31:38
PM
room_entered
room: Main
zone: P_Br_WstEnd
zone_context:
View
Log
7/10/2007
2:31:35
PM
rpc_priv
account: 1942
name: ZoneToPlayer
View
Log
7/10/2007
2:31:27
PM
rpc_priv
account: 1942
name: SendSystemChat
View
Log
7/10/2007
2:31:27
PM
chat_system
message: Ahoy! I'm your duty GM. If you are
experiencing problems, feel free to send me a tell
(/tell GM Rhaegar, message). If you need to report
a bug, please do so via
http://support.flyinglab.com
View
Log
7/10/2007
2:27:47
PM
rpc_priv
account: 1942
name: RequestCharacterInfo
View
Log
7/10/2007
2:26:40
PM
chat_direct
partner: 1042
message: Hi there - the best place to find info like
that is Nation chat
View
Log
7/10/2007
2:16:55
PM
rpc_priv
account: 1942
name: ZoneToPlayer
View
Log
7/10/2007
2:15:11
PM
rpc_priv
account: 1942
name: ZoneToPlayer
View
Log
7/10/2007
2:14:48
PM
rpc_priv
account: 1942
name: SystemWho
View
Log
Money Gained
Reason
money_gained_mission
money_gained_trade
money_gained_kill
money_gained_auction
money_gained_shop
money_gained_create_society
money_gained_respec
money_gained_mail
Amount
31,310,500
11,038,331
8,029,993
6,826,344
4,123,899
13,000
1,263
350
Money Lost
Reason
Amount
money_lost_trade
11,038,331
money_lost_recipe
10,980,920
money_lost_auction
9,956,249
money_lost_shop
7,587,867
money_lost_ActivateStructureDeed
4,760,800
money_lost_admin
3,338,500
money_lost_recipe_tax
633,113
money_lost_PayStructureUpkeep
510,225
money_lost_auction_listing_fee
159,867
money_lost_create_society
89,000
money_lost_mail
14,550
money_lost_AuctionRelist
1,566
Exploit Detection
Character XP Velocity Date
10589
10,713 8/20/2007
10589
10,098 8/19/2007
11268
9,097 8/17/2007
515
8,370 8/18/2007
11077
8,316 8/19/2007
7237
8,226 8/18/2007
3344
7,522 8/20/2007
6801
7,275 8/17/2007
310
7,063 8/21/2007
Reports using context
Context is available in the data
 Extracting it can be slow
 Example: Deaths per level

Current level function
CREATE FUNCTION level_at_flog (@iObject INT, @iCluster INT,
@iFlogId BIGINT)
RETURNS INT AS BEGIN
DECLARE @iLevel INT
SELECT TOP 1 @iLevel = flog_level.value
FROM flog INNER JOIN flog_level ON flog.id=flog_level.id
WHERE (flog.id < @iFlogID) AND
flog.object_id=@iObject AND flog.cluster_id = @iCluster AND
flog.flog_type=3
ORDER BY flog.id DESC
IF @iLevel IS NULL SET @iLevel=1
RETURN @iLevel
END
Death by level table
CREATE TABLE death_by_level
(id BIGINT,
level INT,
object_id INT,
cluster_id INT)
Death by level table
INSERT INTO death_by_level
(id, level, object_id, cluster_id)
SELECT flog.id,
dbo.level_at_flog(flog.object_id,
flog.cluster_id, flog.id) AS [Level],
flog.object_id, flog.cluster_id
FROM flog WHERE flog.flog_type=65
Death by level table
id
130804
199407
231699
242162
348568
382145
384861
390520
402353
423383
Level
7
3
7
4
8
7
8
8
9
9
object_id
1
45
41
43
74
75
86
86
22
33
cluster_id
0
0
0
0
0
0
0
0
0
0
Death by level report
SELECT
level,
COUNT(id) AS [Deaths]
FROM death_by_level
GROUP BY level
ORDER BY level
More data from context
Death by zone
 Death by mission
 XP by zone
 Skills purchased by level
 Play time per level

Room to improve
More and better reports
 Automatic data rollups
 Parameterized queries
 Multiple associated fields in one table
 Performance

Questions?
Slides available at http://programmerjoe.com
Joe Ludwig
[email protected]