Path: blob/master/Core/Debugger/WebSocket/LogBroadcaster.cpp
3187 views
// Copyright (c) 2018- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include <algorithm>18#include <mutex>19#include "Common/Log/LogManager.h"20#include "Core/Debugger/WebSocket/LogBroadcaster.h"21#include "Core/Debugger/WebSocket/WebSocketUtils.h"2223class DebuggerLogListener {24public:25void Log(const LogMessage &msg) {26std::lock_guard<std::mutex> guard(lock_);27messages_[nextMessage_] = msg;28nextMessage_++;29if (nextMessage_ >= BUFFER_SIZE)30nextMessage_ -= BUFFER_SIZE;31count_++;32}3334std::vector<LogMessage> GetMessages() {35std::lock_guard<std::mutex> guard(lock_);36int splitPoint;37int readCount;38if (read_ + BUFFER_SIZE < count_) {39// We'll start with our oldest then.40splitPoint = nextMessage_;41readCount = Count();42} else {43splitPoint = read_;44readCount = count_ - read_;45}4647read_ = count_;4849std::vector<LogMessage> results;50int splitEnd = std::min(splitPoint + readCount, (int)BUFFER_SIZE);51for (int i = splitPoint; i < splitEnd; ++i) {52results.push_back(messages_[i]);53readCount--;54}55for (int i = 0; i < readCount; ++i) {56results.push_back(messages_[i]);57}5859return results;60}6162int Count() const {63return count_ < BUFFER_SIZE ? count_ : BUFFER_SIZE;64}6566private:67enum { BUFFER_SIZE = 1024 };68LogMessage messages_[BUFFER_SIZE];69std::mutex lock_;70int nextMessage_ = 0;71int count_ = 0;72int read_ = 0;73};7475static void BroadcastCallback(const LogMessage &message, void *userdata) {76DebuggerLogListener *listener = (DebuggerLogListener *)userdata;77listener->Log(message);78}7980LogBroadcaster::LogBroadcaster() {81listener_ = new DebuggerLogListener();82g_logManager.SetExternalLogCallback(&BroadcastCallback, (void *)listener_);83g_logManager.EnableOutput(LogOutput::ExternalCallback);84}8586LogBroadcaster::~LogBroadcaster() {87g_logManager.DisableOutput(LogOutput::ExternalCallback);88g_logManager.SetExternalLogCallback(nullptr, nullptr);89delete listener_;90}9192struct DebuggerLogEvent {93const LogMessage &l;9495operator std::string() {96JsonWriter j;97j.begin();98j.writeString("event", "log");99j.writeString("timestamp", l.timestamp);100j.writeString("header", l.header);101j.writeString("message", l.msg);102j.writeInt("level", (int)l.level);103j.writeString("channel", l.log);104j.end();105return j.str();106}107};108109// Log message (log)110//111// Sent unexpectedly with these properties:112// - timestamp: string timestamp of event.113// - header: string header information about the event (including file/line.)114// - message: actual log message as a string.115// - level: number severity level (1 = highest.)116// - channel: string describing log channel / grouping.117void LogBroadcaster::Broadcast(net::WebSocketServer *ws) {118auto messages = listener_->GetMessages();119for (auto msg : messages) {120ws->Send(DebuggerLogEvent{msg});121}122}123124125