Error tracking with Sentry on Roblox

The free tier for Sentry seems rather low even for low-traffic Roblox games

image

That’s only 13 events per hour, or 0.22 per minute. Even at the next tier (26$/mo), you only get 100k so 2.2 per minute for your entire game.

The module is cool though! But maybe you can extend it to work with other services too? (I can imagine 90% of the source of your module can be reused)

EDIT: For reference: our game with ~50-200 concurrent players generates about 270k records per month already, all logging levels combined. I would need to pay ~180-200$/mo to Sentry to support that, while we have our own database + interface for basically free at the moment.

EDIT2: Yikes, bugsnag is even more expensive for the number of events per month that they offer… I think we’re going to stick with what we have for now :stuck_out_tongue:

5 Likes

Yeah, their rate limiting is awful, especially for the free tiers. GameAnalytics might be a much better option since AFAIK there is no limit aside from unique events. As long as you generalize errors (i.e. game.Players.EchoReaper.Backpack.Tool.Script : 40 -> <PLAYER>.Backpack.Tool.Script : 40) you should be fine.

Another alternative would be to log errors in the DataStore, and if you can’t save to DataStores, use Sentry/etc as a fallback.

2 Likes

You mention 270k records per month, all logging levels combined. Are you tracking records other than errors, or are all those events in some way another an error?

1 Like

If you just don’t log errors, it’s like they never happen

22 Likes

That’s why Farming among Friends has no bugs!

Well, I do have it linked to google analytics but I never check it.

2 Likes

All of those 270k are errors or warnings or debugging-related info logs (minor amount) in some way. A big part of it (recently) came from chat-related CoreScripts and other Roblox-managed things though so we could theoretically filter out those messages to reduce the load.

Sentry doesn’t have very large limits for its free tier, but the major sellers for me are: its interface, (relative) ease of use, and the fact that events are, most of the time, instantly processed.

It’s definitely not for logging a lot of debug information or general statistics (there’s GameAnalytics for that), but under the right circumstances I believe it can be invaluable.

Sentry should probably be integrated in a public/private testing/release stage after most surface bugs have been fixed, when the more contextual bugs rarely rear their heads. At that stage, I doubt a large amount of developers would be encountering >10k events/month, as long as they stay on top of frequently-occurring bugs.

Even if that limit were reached, you’d have the last seven days of potentially a month’s worth of data to work with, which is infinitely better than nothing.

I’ve just used a Discord webhook that makes a message in the server’s Error Log channel. It posts the error and it’s trace. I never seem to run into issues with it. The only problem would be if a game becomes popular and there a could be multiple errors and I have to search for the right one.

2 Likes

Reply 1 (below)

See also:
Reply 2
Reply 3
And the rest of that thread.

3 Likes

It’s fine actually so long as they don’t hit the rate limits.

https://devforum.roblox.com/t/discord-and-trello-api-communication-bots/49670/14

2 Likes

Definitely don’t use the free Sentry SaaS. The best option for using Sentry is to host it yourself. They provide a Docker image which requires a fair bit of setup and might be advanced for some users, but if you’re willing to go through that, you can log as many events as you want for as much as your server costs.

P.S. @nomer888 I would highly recommend changing eventLevel.fatal to EventLevel.Fatal, ExceptionType.Server, etc. to stay aligned with the ROBLOX “enum” conventions.

P.P.S. If anyone’s interested in a tutorial on how to set it up, I might be able to dedicate some time to writing one.

5 Likes

I agree with you on the enum conventions, I’ve fixed that.

However, why do you recommend not using Sentry’s free offerings? It’s definitely not as good as hosting it yourself, but for most it’s a quick, easy, and a good enough solution you can pop into your game in < 1 hour and forget about it. Like Crazyman said, if you don’t log errors at all, it’s like they never happen- and this can get you started, at the least.

That being said, I am interested in a tutorial on how to set something like that up.

I don’t recommend using it because of the low quotas. However, if you don’t have that many events and the free tier works for you, go for it. It’s just that hosting it yourself is much better because there’s no limitations.

2 Likes

Found this thread because I ended up getting a Sponsored Sentry plan through the Github Student Developer Pack, which gives me 500k events/mo for free while I’m a student. (I highly suggest signing up for this if you’re in school, and even if you aren’t you can still apply and get some free goodies)

Thanks for this module, I plan to use it soon for an upcoming project!

3 Likes

Nice! Lemme know if there are any features you want or bugs with this and I’ll address them as soon as I can.

Aha Same, Got the pack a month ago and was wondering if anyone made a tutorial for sentry.

1 Like

So I’m using ScriptContext.Error as a catch-all handler for all Errors that can occur in the game and then sending them to Sentry. The only problem I’ve come across is that the trace that is passed by ScriptContext.Error is not the same format as debug.traceback().

So I ended up adding this to the StringTraceToTable() function.
The main addition is matching for the trace format that ScriptContext.Error uses, and then recording them as path2, lineNum2, value2 respectively.

local function StringTraceToTable(trace)
	local stacktrace = {}

	for line in trace:gmatch("[^\n\r]+") do
		if (not line:match("^Stack Begin$") and not line:match("^Stack End$")) then
			local path, lineNum, value = line:match("^Script '(.-)', Line (%d+)%s?%-?%s?(.*)$")
			local path2, lineNum2, value2 = line:match("^(.-), line (%d+)%s?%-?%s?(.*)$")
			print(path2, lineNum2, value2)
			if (path and lineNum and value) then
				stacktrace[#stacktrace + 1] = {
					filename = path;
					["function"] = value or "nil";
					lineno = lineNum;
				}
			elseif (path2 and lineNum2 and value2) then
				stacktrace[#stacktrace + 1] = {
					filename = path2;
					["function"] = value2 or "nil";
					lineno = lineNum2;
				}
			else
				return false, "invalid traceback"
			end
		end
	end

	if (#stacktrace == 0) then
		return false, "invalid traceback"
	end

	local sorted = {}
	for i = #stacktrace, 1, -1 do
		sorted[i] = stacktrace[i]
	end

	return true, sorted
end
1 Like

I figured out how you can log all errors and send it to raven. Here’s how:
Make a new script in serverscriptservice to require the module and set the client like so

local Raven = require(game.ReplicatedStorage.Raven)
     
local client = Raven:Client("DSN here")

then use scriptcontext to log all errors that happen like so

game:GetService("ScriptContext").Error:Connect(function(message,trace,script)

    client:SendException(Raven.ExceptionType.Server, message, debug.traceback())

end)

then for the remote event for client you would type this:

client:ConnectRemoteEvent(Instance.new("RemoteEvent", game.ReplicatedStorage))

for client errors you would put a local script in starterplayer.starterplayerscripts and put the following code to send the info to the server

game:GetService("ScriptContext").Error:Connect(function(message,trace,script)

    game.ReplicatedStorage.RemoteEvent:FireServer(message, debug.traceback())

end)

Hope this helps you guys who are struggling with this :slight_smile:

I’m sorry but what is Raven? Is it a model, is it something owned by Sentry?

“Raven” is the name of the module that OP is using.
You can find it here: https://gitlab.com/nomer888/rbxlua-raven

2 Likes