Log.SetupLevel("\073\110\102\111",1)Log.SetupLevel("\068\101\098\117\103",2)Log.SetupLevel("\087\097\114\110",3)Log.SetupLevel("\069\114\114\111\114",4)function Log.Log(f,C,...)local c=string.format(...)local O=Log._LevelName[f]if _messageQueue then if not _remoteFilterFunc or not _remoteFilterFunc(f,O,C,c)then table.insert(_messageQueue,{tick(),f;C;c})end end if _consoleFilterFunc and _consoleFilterFunc(f,O,C,c)then return end if C then print(string.format("\091\037\115\093\091\037\115\093",O,C),c)else print(string.format("\091\037\115\093",O),c)end end Log.Data=setmetatable({},{__index=function(f,C)return function(...)Log.LogData(C,...)end end})function Log.LogData(f,C)if _messageQueue then table.insert(_messageQueue,{tick(),"\100\097\116\097";f;C})end end function Log.ProcessQueue(f)if not _messageQueue then return end if _isClient then _remoteEvent:FireServer(_messageQueue)elseif f and#_messageQueue>0 then local C={place=game.PlaceId,game=game.GameId;job=game.JobId;messages=_messageQueue}HttpService:PostAsync(f,HttpService:JSONEncode(C),Enum.HttpContentType.ApplicationJson,false)end Log.ClearQueue()end local function f(f,C)if _messageQueue and#C>0 then table.insert(_messageQueue,{player=f.UserId,messages=C})end end function Log.wrapSystemMessages()LogService.MessageOut:connect(function(f,C)if string.match(f,"\094\037\091\091\094\037\093\093\043\037\093")then return end Log.Log(C.Value+1,"\083\089\083\084\069\077","\037\115",f)end)end function Log.EnableQueue(f)if f and not _messageQueue then _messageQueue={}end if not f then _messageQueue=nil end end function Log.ClearQueue()for f,C in pairs(_messageQueue)do _messageQueue[f]=nil end end function Log.SetRemoteFilterFunc(f)_remoteFilterFunc=f end function Log.SetConsoleFilterFunc(f)_consoleFilterFunc=f end local function C()return true end

Log.SetupLevel('Info', 1)
Log.SetupLevel('Debug', 2)
Log.SetupLevel('Warn', 3)
Log.SetupLevel('Error', 4)

function Log.Log(level, chan, ...)
	local msg = string.format(...)
	local levelName = Log._LevelName[level]

	if _messageQueue then
		if not _remoteFilterFunc or not _remoteFilterFunc(level, levelName, chan, msg) then
			table.insert(_messageQueue, {tick(), level, chan, msg})
		end
	end

	if _consoleFilterFunc and _consoleFilterFunc(level, levelName, chan, msg) then
		return;
	end

	if chan then
		print(string.format("[%s][%s]", levelName, chan), msg)
	else
		print(string.format("[%s]", levelName), msg)
	end
end

Log.Data =
	setmetatable({}, {
			__index = function(tbl, key)
				return function(...)
					Log.LogData(key, ...)
				end
			end;
	})

function Log.LogData(chan, data)
	if _messageQueue then
		table.insert(_messageQueue, {tick(), 'data', chan, data})
	end
end

function Log.ProcessQueue(remote)
	if not _messageQueue then
		return
	end

	-- As a naive first pass, let's just send all of it at once.

	if _isClient then
		_remoteEvent:FireServer(_messageQueue)

	elseif remote and #_messageQueue > 0 then
		-- TODO:  Count connection errors and stop attempting remote connections if it can't be reached
		-- .Experiment with compression
		local data = {
			place = game.PlaceId,
			game = game.GameId,
			job = game.JobId,
			messages = _messageQueue,
		}

		HttpService:PostAsync(remote,
							  HttpService:JSONEncode(data),
							  Enum.HttpContentType.ApplicationJson,
							  false)
	end

	Log.ClearQueue()
end

local function onClientLogging(player, messages)
	if _messageQueue and #messages > 0 then
		table.insert(_messageQueue, {player = player.UserId, messages = messages })
	end
end

function Log.wrapSystemMessages()
	LogService.MessageOut:connect(function(msg, msgType)
			-- HACK:  Have to detect our logging messages vs. system level ones
			if string.match(msg, '^%[[^%]]+%]') then
				return
			end

			-- NOTE:  +1 more or less automatically maps to the current built-in log levels
			Log.Log(msgType.Value + 1, 'SYSTEM', "%s", msg)
	end)
end

function Log.EnableQueue(state)
	if state and not _messageQueue then
		_messageQueue = {}
	end

	if not state then
		_messageQueue = nil
	end
end

function Log.ClearQueue()
	for k,v in pairs(_messageQueue) do
		_messageQueue[k] = nil
	end
end

function Log.SetRemoteFilterFunc(func)
	_remoteFilterFunc = func
end

function Log.SetConsoleFilterFunc(func)
	_consoleFilterFunc = func
end

local function _remoteFilterEverything()
	return true
end
