Added option to log streams by their ID, allowing for easier "per-stream" log analyzing (#5507)

This commit is contained in:
pajlada 2024-07-14 11:45:21 +02:00 committed by GitHub
parent b9f669d3a5
commit 9788d0f8f7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 150 additions and 68 deletions

View file

@ -15,6 +15,7 @@
- Minor: Added support for Brave & google-chrome-stable browsers. (#5452) - Minor: Added support for Brave & google-chrome-stable browsers. (#5452)
- Minor: Added drop indicator line while dragging in tables. (#5256) - Minor: Added drop indicator line while dragging in tables. (#5256)
- Minor: Add channel points indication for new bits power-up redemptions. (#5471) - Minor: Add channel points indication for new bits power-up redemptions. (#5471)
- Minor: Added option to log streams by their ID, allowing for easier "per-stream" log analyzing. (#5507)
- Minor: Added `/warn <username> <reason>` command for mods. This prevents the user from chatting until they acknowledge the warning. (#5474) - Minor: Added `/warn <username> <reason>` command for mods. This prevents the user from chatting until they acknowledge the warning. (#5474)
- Minor: Improve appearance of reply button. (#5491) - Minor: Improve appearance of reply button. (#5491)
- Minor: Introduce HTTP API for plugins. (#5383, #5492, #5494) - Minor: Introduce HTTP API for plugins. (#5383, #5492, #5494)

View file

@ -16,7 +16,7 @@ public:
MOCK_METHOD(void, addMessage, MOCK_METHOD(void, addMessage,
(const QString &channelName, MessagePtr message, (const QString &channelName, MessagePtr message,
const QString &platformName), const QString &platformName, const QString &streamID),
(override)); (override));
}; };
@ -27,7 +27,8 @@ public:
~EmptyLogging() override = default; ~EmptyLogging() override = default;
void addMessage(const QString &channelName, MessagePtr message, void addMessage(const QString &channelName, MessagePtr message,
const QString &platformName) override const QString &platformName,
const QString &streamID) override
{ {
// //
} }

View file

@ -101,7 +101,8 @@ void Channel::addMessage(MessagePtr message, MessageContext context,
{ {
// Only log messages where the `DoNotLog` flag is not set // Only log messages where the `DoNotLog` flag is not set
getIApp()->getChatLogger()->addMessage(this->name_, message, getIApp()->getChatLogger()->addMessage(this->name_, message,
this->platform_); this->platform_,
this->getCurrentStreamID());
} }
} }
@ -356,6 +357,11 @@ void Channel::reconnect()
{ {
} }
QString Channel::getCurrentStreamID() const
{
return {};
}
std::shared_ptr<Channel> Channel::getEmpty() std::shared_ptr<Channel> Channel::getEmpty()
{ {
static std::shared_ptr<Channel> channel(new Channel("", Type::None)); static std::shared_ptr<Channel> channel(new Channel("", Type::None));

View file

@ -119,6 +119,7 @@ public:
virtual bool shouldIgnoreHighlights() const; virtual bool shouldIgnoreHighlights() const;
virtual bool canReconnect() const; virtual bool canReconnect() const;
virtual void reconnect(); virtual void reconnect();
virtual QString getCurrentStreamID() const;
static std::shared_ptr<Channel> getEmpty(); static std::shared_ptr<Channel> getEmpty();

View file

@ -457,6 +457,7 @@ void TwitchChannel::updateStreamStatus(
auto stream = *helixStream; auto stream = *helixStream;
{ {
auto status = this->streamStatus_.access(); auto status = this->streamStatus_.access();
status->streamId = stream.id;
status->viewerCount = stream.viewerCount; status->viewerCount = stream.viewerCount;
status->gameId = stream.gameId; status->gameId = stream.gameId;
status->game = stream.gameName; status->game = stream.gameName;
@ -770,6 +771,17 @@ void TwitchChannel::reconnect()
getIApp()->getTwitchAbstract()->connect(); getIApp()->getTwitchAbstract()->connect();
} }
QString TwitchChannel::getCurrentStreamID() const
{
auto streamStatus = this->accessStreamStatus();
if (streamStatus->live)
{
return streamStatus->streamId;
}
return {};
}
QString TwitchChannel::roomId() const QString TwitchChannel::roomId() const
{ {
return *this->roomID_.access(); return *this->roomID_.access();

View file

@ -87,6 +87,7 @@ public:
QString uptime; QString uptime;
int uptimeSeconds = 0; int uptimeSeconds = 0;
QString streamType; QString streamType;
QString streamId;
}; };
struct RoomModes { struct RoomModes {
@ -133,6 +134,7 @@ public:
bool hasHighRateLimit() const override; bool hasHighRateLimit() const override;
bool canReconnect() const override; bool canReconnect() const override;
void reconnect() override; void reconnect() override;
QString getCurrentStreamID() const override;
void createClip(); void createClip();
// Data // Data

View file

@ -33,7 +33,7 @@ Logging::Logging(Settings &settings)
} }
void Logging::addMessage(const QString &channelName, MessagePtr message, void Logging::addMessage(const QString &channelName, MessagePtr message,
const QString &platformName) const QString &platformName, const QString &streamID)
{ {
this->threadGuard.guard(); this->threadGuard.guard();
@ -54,7 +54,7 @@ void Logging::addMessage(const QString &channelName, MessagePtr message,
if (platIt == this->loggingChannels_.end()) if (platIt == this->loggingChannels_.end())
{ {
auto *channel = new LoggingChannel(channelName, platformName); auto *channel = new LoggingChannel(channelName, platformName);
channel->addMessage(message); channel->addMessage(message, streamID);
auto map = std::map<QString, std::unique_ptr<LoggingChannel>>(); auto map = std::map<QString, std::unique_ptr<LoggingChannel>>();
this->loggingChannels_[platformName] = std::move(map); this->loggingChannels_[platformName] = std::move(map);
auto &ref = this->loggingChannels_.at(platformName); auto &ref = this->loggingChannels_.at(platformName);
@ -65,12 +65,12 @@ void Logging::addMessage(const QString &channelName, MessagePtr message,
if (chanIt == platIt->second.end()) if (chanIt == platIt->second.end())
{ {
auto *channel = new LoggingChannel(channelName, platformName); auto *channel = new LoggingChannel(channelName, platformName);
channel->addMessage(message); channel->addMessage(message, streamID);
platIt->second.emplace(channelName, std::move(channel)); platIt->second.emplace(channelName, std::move(channel));
} }
else else
{ {
chanIt->second->addMessage(message); chanIt->second->addMessage(message, streamID);
} }
} }

View file

@ -22,7 +22,8 @@ public:
virtual ~ILogging() = default; virtual ~ILogging() = default;
virtual void addMessage(const QString &channelName, MessagePtr message, virtual void addMessage(const QString &channelName, MessagePtr message,
const QString &platformName) = 0; const QString &platformName,
const QString &streamID) = 0;
}; };
class Logging : public ILogging class Logging : public ILogging
@ -31,7 +32,8 @@ public:
Logging(Settings &settings); Logging(Settings &settings);
void addMessage(const QString &channelName, MessagePtr message, void addMessage(const QString &channelName, MessagePtr message,
const QString &platformName) override; const QString &platformName,
const QString &streamID) override;
private: private:
using PlatformName = QString; using PlatformName = QString;

View file

@ -447,6 +447,10 @@ public:
BoolSetting enableLogging = {"/logging/enabled", false}; BoolSetting enableLogging = {"/logging/enabled", false};
BoolSetting onlyLogListedChannels = {"/logging/onlyLogListedChannels", BoolSetting onlyLogListedChannels = {"/logging/onlyLogListedChannels",
false}; false};
BoolSetting separatelyStoreStreamLogs = {
"/logging/separatelyStoreStreamLogs",
false,
};
QStringSetting logPath = {"/logging/path", ""}; QStringSetting logPath = {"/logging/path", ""};

View file

@ -1,4 +1,4 @@
#include "LoggingChannel.hpp" #include "singletons/helper/LoggingChannel.hpp"
#include "Application.hpp" #include "Application.hpp"
#include "common/QLogging.hpp" #include "common/QLogging.hpp"
@ -7,16 +7,58 @@
#include "singletons/Paths.hpp" #include "singletons/Paths.hpp"
#include "singletons/Settings.hpp" #include "singletons/Settings.hpp"
#include <QDateTime>
#include <QDir> #include <QDir>
namespace {
const QByteArray ENDLINE("\n");
void appendLine(QFile &fileHandle, const QString &line)
{
assert(fileHandle.isOpen());
assert(fileHandle.isWritable());
fileHandle.write(line.toUtf8());
fileHandle.flush();
}
QString generateOpeningString(
const QDateTime &now = QDateTime::currentDateTime())
{
QString ret("# Start logging at ");
ret.append(now.toString("yyyy-MM-dd HH:mm:ss "));
ret.append(now.timeZoneAbbreviation());
ret.append(ENDLINE);
return ret;
}
QString generateClosingString(
const QDateTime &now = QDateTime::currentDateTime())
{
QString ret("# Stop logging at ");
ret.append(now.toString("yyyy-MM-dd HH:mm:ss"));
ret.append(now.timeZoneAbbreviation());
ret.append(ENDLINE);
return ret;
}
QString generateDateString(const QDateTime &now)
{
return now.toString("yyyy-MM-dd");
}
} // namespace
namespace chatterino { namespace chatterino {
QByteArray endline("\n"); LoggingChannel::LoggingChannel(QString _channelName, QString _platform)
: channelName(std::move(_channelName))
LoggingChannel::LoggingChannel(const QString &_channelName, , platform(std::move(_platform))
const QString &_platform)
: channelName(_channelName)
, platform(_platform)
{ {
if (this->channelName.startsWith("/whispers")) if (this->channelName.startsWith("/whispers"))
{ {
@ -54,14 +96,15 @@ LoggingChannel::LoggingChannel(const QString &_channelName,
LoggingChannel::~LoggingChannel() LoggingChannel::~LoggingChannel()
{ {
this->appendLine(this->generateClosingString()); appendLine(this->fileHandle, generateClosingString());
this->fileHandle.close(); this->fileHandle.close();
this->currentStreamFileHandle.close();
} }
void LoggingChannel::openLogFile() void LoggingChannel::openLogFile()
{ {
QDateTime now = QDateTime::currentDateTime(); QDateTime now = QDateTime::currentDateTime();
this->dateString = this->generateDateString(now); this->dateString = generateDateString(now);
if (this->fileHandle.isOpen()) if (this->fileHandle.isOpen())
{ {
@ -87,14 +130,45 @@ void LoggingChannel::openLogFile()
this->fileHandle.open(QIODevice::Append); this->fileHandle.open(QIODevice::Append);
this->appendLine(this->generateOpeningString(now)); appendLine(this->fileHandle, generateOpeningString(now));
} }
void LoggingChannel::addMessage(MessagePtr message) void LoggingChannel::openStreamLogFile(const QString &streamID)
{
QDateTime now = QDateTime::currentDateTime();
this->currentStreamID = streamID;
if (this->currentStreamFileHandle.isOpen())
{
this->currentStreamFileHandle.flush();
this->currentStreamFileHandle.close();
}
QString baseFileName = this->channelName + "-" + streamID + ".log";
QString directory =
this->baseDirectory + QDir::separator() + this->subDirectory;
if (!QDir().mkpath(directory))
{
qCDebug(chatterinoHelper) << "Unable to create logging path";
return;
}
QString fileName = directory + QDir::separator() + baseFileName;
qCDebug(chatterinoHelper) << "Logging stream to" << fileName;
this->currentStreamFileHandle.setFileName(fileName);
this->currentStreamFileHandle.open(QIODevice::Append);
appendLine(this->currentStreamFileHandle, generateOpeningString(now));
}
void LoggingChannel::addMessage(const MessagePtr &message,
const QString &streamID)
{ {
QDateTime now = QDateTime::currentDateTime(); QDateTime now = QDateTime::currentDateTime();
QString messageDateString = this->generateDateString(now); QString messageDateString = generateDateString(now);
if (messageDateString != this->dateString) if (messageDateString != this->dateString)
{ {
this->dateString = messageDateString; this->dateString = messageDateString;
@ -154,42 +228,19 @@ void LoggingChannel::addMessage(MessagePtr message)
} }
} }
str.append(messageText); str.append(messageText);
str.append(endline); str.append(ENDLINE);
this->appendLine(str); appendLine(this->fileHandle, str);
}
QString LoggingChannel::generateOpeningString(const QDateTime &now) const if (!streamID.isEmpty() && getSettings()->separatelyStoreStreamLogs)
{ {
QString ret("# Start logging at "); if (this->currentStreamID != streamID)
{
this->openStreamLogFile(streamID);
}
ret.append(now.toString("yyyy-MM-dd HH:mm:ss ")); appendLine(this->currentStreamFileHandle, str);
ret.append(now.timeZoneAbbreviation()); }
ret.append(endline);
return ret;
}
QString LoggingChannel::generateClosingString(const QDateTime &now) const
{
QString ret("# Stop logging at ");
ret.append(now.toString("yyyy-MM-dd HH:mm:ss"));
ret.append(now.timeZoneAbbreviation());
ret.append(endline);
return ret;
}
void LoggingChannel::appendLine(const QString &line)
{
this->fileHandle.write(line.toUtf8());
this->fileHandle.flush();
}
QString LoggingChannel::generateDateString(const QDateTime &now)
{
return now.toString("yyyy-MM-dd");
} }
} // namespace chatterino } // namespace chatterino

View file

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <QDateTime>
#include <QFile> #include <QFile>
#include <QString> #include <QString>
@ -14,8 +13,7 @@ using MessagePtr = std::shared_ptr<const Message>;
class LoggingChannel class LoggingChannel
{ {
explicit LoggingChannel(const QString &_channelName, explicit LoggingChannel(QString _channelName, QString _platform);
const QString &platform);
public: public:
~LoggingChannel(); ~LoggingChannel();
@ -26,19 +24,11 @@ public:
LoggingChannel(LoggingChannel &&) = delete; LoggingChannel(LoggingChannel &&) = delete;
LoggingChannel &operator=(LoggingChannel &&) = delete; LoggingChannel &operator=(LoggingChannel &&) = delete;
void addMessage(MessagePtr message); void addMessage(const MessagePtr &message, const QString &streamID);
private: private:
void openLogFile(); void openLogFile();
void openStreamLogFile(const QString &streamID);
QString generateOpeningString(
const QDateTime &now = QDateTime::currentDateTime()) const;
QString generateClosingString(
const QDateTime &now = QDateTime::currentDateTime()) const;
void appendLine(const QString &line);
QString generateDateString(const QDateTime &now);
const QString channelName; const QString channelName;
const QString platform; const QString platform;
@ -46,6 +36,8 @@ private:
QString subDirectory; QString subDirectory;
QFile fileHandle; QFile fileHandle;
QFile currentStreamFileHandle;
QString currentStreamID;
QString dateString; QString dateString;

View file

@ -157,11 +157,21 @@ ModerationPage::ModerationPage()
onlyLogListedChannels->setEnabled(getSettings()->enableLogging); onlyLogListedChannels->setEnabled(getSettings()->enableLogging);
logs.append(onlyLogListedChannels); logs.append(onlyLogListedChannels);
auto *separatelyStoreStreamLogs =
this->createCheckBox("Store live stream logs as separate files",
getSettings()->separatelyStoreStreamLogs);
separatelyStoreStreamLogs->setEnabled(getSettings()->enableLogging);
logs.append(separatelyStoreStreamLogs);
// Select event // Select event
QObject::connect( QObject::connect(
enableLogging, &QCheckBox::stateChanged, this, enableLogging, &QCheckBox::stateChanged, this,
[enableLogging, onlyLogListedChannels]() mutable { [enableLogging, onlyLogListedChannels,
separatelyStoreStreamLogs]() mutable {
onlyLogListedChannels->setEnabled(enableLogging->isChecked()); onlyLogListedChannels->setEnabled(enableLogging->isChecked());
separatelyStoreStreamLogs->setEnabled(
getSettings()->enableLogging);
}); });
EditableModelView *view = EditableModelView *view =