mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-06-23 15:30:34 -04:00
Extra Stat collection (#407)
* Cleaned up error interceptor to avoid sending auth errors (when a 500 occurs) to sentry as auth errors aren't issues. * Added extra stat collection * Fixed a bad gitignore which ignored anything in a stats directory
This commit is contained in:
parent
b9a06d3586
commit
b11bb0e3b5
4
.gitignore
vendored
4
.gitignore
vendored
@ -491,11 +491,11 @@ appsettings.json
|
|||||||
/API/kavita.db-wal
|
/API/kavita.db-wal
|
||||||
/API/Hangfire.db
|
/API/Hangfire.db
|
||||||
/API/Hangfire-log.db
|
/API/Hangfire-log.db
|
||||||
cache/
|
API/cache/
|
||||||
/API/wwwroot/
|
/API/wwwroot/
|
||||||
/API/cache/
|
/API/cache/
|
||||||
/API/temp/
|
/API/temp/
|
||||||
_temp/
|
_temp/
|
||||||
_output/
|
_output/
|
||||||
stats/
|
API/stats/
|
||||||
UI/Web/dist/
|
UI/Web/dist/
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using API.DTOs;
|
using API.DTOs.Stats;
|
||||||
using API.Extensions;
|
using API.Extensions;
|
||||||
using API.Interfaces.Services;
|
using API.Interfaces.Services;
|
||||||
using API.Services;
|
using API.Services.Tasks;
|
||||||
using Kavita.Common;
|
using Kavita.Common;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using API.DTOs;
|
using API.DTOs.Stats;
|
||||||
using API.Interfaces.Services;
|
using API.Interfaces.Services;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace API.DTOs
|
namespace API.DTOs.Stats
|
||||||
{
|
{
|
||||||
public class ClientInfoDto
|
public class ClientInfoDto
|
||||||
{
|
{
|
||||||
@ -16,13 +16,14 @@ namespace API.DTOs
|
|||||||
public DetailsVersion Os { get; set; }
|
public DetailsVersion Os { get; set; }
|
||||||
|
|
||||||
public DateTime? CollectedAt { get; set; }
|
public DateTime? CollectedAt { get; set; }
|
||||||
|
public bool UsingDarkTheme { get; set; }
|
||||||
|
|
||||||
public bool IsTheSameDevice(ClientInfoDto clientInfoDto)
|
public bool IsTheSameDevice(ClientInfoDto clientInfoDto)
|
||||||
{
|
{
|
||||||
return (clientInfoDto.ScreenResolution ?? "").Equals(ScreenResolution) &&
|
return (clientInfoDto.ScreenResolution ?? string.Empty).Equals(ScreenResolution) &&
|
||||||
(clientInfoDto.PlatformType ?? "").Equals(PlatformType) &&
|
(clientInfoDto.PlatformType ?? string.Empty).Equals(PlatformType) &&
|
||||||
(clientInfoDto.Browser?.Name ?? "").Equals(Browser?.Name) &&
|
(clientInfoDto.Browser?.Name ?? string.Empty).Equals(Browser?.Name) &&
|
||||||
(clientInfoDto.Os?.Name ?? "").Equals(Os?.Name) &&
|
(clientInfoDto.Os?.Name ?? string.Empty).Equals(Os?.Name) &&
|
||||||
clientInfoDto.CollectedAt.GetValueOrDefault().ToString("yyyy-MM-dd")
|
clientInfoDto.CollectedAt.GetValueOrDefault().ToString("yyyy-MM-dd")
|
||||||
.Equals(CollectedAt.GetValueOrDefault().ToString("yyyy-MM-dd"));
|
.Equals(CollectedAt.GetValueOrDefault().ToString("yyyy-MM-dd"));
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
namespace API.DTOs
|
namespace API.DTOs.Stats
|
||||||
{
|
{
|
||||||
public class ServerInfoDto
|
public class ServerInfoDto
|
||||||
{
|
{
|
||||||
@ -8,5 +8,7 @@
|
|||||||
public string KavitaVersion { get; set; }
|
public string KavitaVersion { get; set; }
|
||||||
public string BuildBranch { get; set; }
|
public string BuildBranch { get; set; }
|
||||||
public string Culture { get; set; }
|
public string Culture { get; set; }
|
||||||
|
public bool IsDocker { get; set; }
|
||||||
|
public int NumOfCores { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using API.Entities.Enums;
|
using API.Entities.Enums;
|
||||||
|
|
||||||
namespace API.DTOs
|
namespace API.DTOs.Stats
|
||||||
{
|
{
|
||||||
public class UsageInfoDto
|
public class UsageInfoDto
|
||||||
{
|
{
|
@ -2,7 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace API.DTOs
|
namespace API.DTOs.Stats
|
||||||
{
|
{
|
||||||
public class UsageStatisticsDto
|
public class UsageStatisticsDto
|
||||||
{
|
{
|
@ -1,5 +1,5 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using API.DTOs;
|
using API.DTOs.Stats;
|
||||||
|
|
||||||
namespace API.Interfaces.Services
|
namespace API.Interfaces.Services
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Json;
|
using System.Net.Http.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using API.DTOs;
|
using API.DTOs.Stats;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace API.Services.Clients
|
namespace API.Services.Clients
|
||||||
|
@ -6,7 +6,7 @@ using System.Text.Json;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using API.Data;
|
using API.Data;
|
||||||
using API.DTOs;
|
using API.DTOs.Stats;
|
||||||
using API.Interfaces;
|
using API.Interfaces;
|
||||||
using API.Interfaces.Services;
|
using API.Interfaces.Services;
|
||||||
using API.Services.Clients;
|
using API.Services.Clients;
|
||||||
@ -15,7 +15,7 @@ using Kavita.Common.EnvironmentInfo;
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace API.Services
|
namespace API.Services.Tasks
|
||||||
{
|
{
|
||||||
public class StatsService : IStatsService
|
public class StatsService : IStatsService
|
||||||
{
|
{
|
||||||
@ -142,7 +142,9 @@ namespace API.Services
|
|||||||
RunTimeVersion = RuntimeInformation.FrameworkDescription,
|
RunTimeVersion = RuntimeInformation.FrameworkDescription,
|
||||||
KavitaVersion = BuildInfo.Version.ToString(),
|
KavitaVersion = BuildInfo.Version.ToString(),
|
||||||
Culture = Thread.CurrentThread.CurrentCulture.Name,
|
Culture = Thread.CurrentThread.CurrentCulture.Name,
|
||||||
BuildBranch = BuildInfo.Branch
|
BuildBranch = BuildInfo.Branch,
|
||||||
|
IsDocker = new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker,
|
||||||
|
NumOfCores = Environment.ProcessorCount
|
||||||
};
|
};
|
||||||
|
|
||||||
return serverInfo;
|
return serverInfo;
|
@ -7,6 +7,7 @@ using API.Services;
|
|||||||
using API.Services.HostedServices;
|
using API.Services.HostedServices;
|
||||||
using Hangfire;
|
using Hangfire;
|
||||||
using Hangfire.MemoryStorage;
|
using Hangfire.MemoryStorage;
|
||||||
|
using Kavita.Common;
|
||||||
using Kavita.Common.EnvironmentInfo;
|
using Kavita.Common.EnvironmentInfo;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
@ -26,10 +26,6 @@ export class ErrorInterceptor implements HttpInterceptor {
|
|||||||
return throwError(error);
|
return throwError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!environment.production) {
|
|
||||||
console.error('error:', error);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (error.status) {
|
switch (error.status) {
|
||||||
case 400:
|
case 400:
|
||||||
this.handleValidationError(error);
|
this.handleValidationError(error);
|
||||||
@ -99,12 +95,15 @@ export class ErrorInterceptor implements HttpInterceptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private handleServerException(error: any) {
|
private handleServerException(error: any) {
|
||||||
console.error('500 error:', error);
|
|
||||||
const err = error.error;
|
const err = error.error;
|
||||||
if (err.hasOwnProperty('message') && err.message.trim() !== '') {
|
if (err.hasOwnProperty('message') && err.message.trim() !== '') {
|
||||||
|
if (err.message != 'User is not authenticated') {
|
||||||
|
console.log('500 error: ', error);
|
||||||
|
}
|
||||||
this.toastr.error(err.message);
|
this.toastr.error(err.message);
|
||||||
} else {
|
} else {
|
||||||
this.toastr.error('There was an unknown critical error.');
|
this.toastr.error('There was an unknown critical error.');
|
||||||
|
console.error('500 error:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ export interface ClientInfo {
|
|||||||
platformType: string,
|
platformType: string,
|
||||||
kavitaUiVersion: string,
|
kavitaUiVersion: string,
|
||||||
screenResolution: string;
|
screenResolution: string;
|
||||||
|
usingDarkTheme: boolean;
|
||||||
|
|
||||||
collectedAt?: Date;
|
collectedAt?: Date;
|
||||||
}
|
}
|
@ -1,7 +1,13 @@
|
|||||||
import { HttpClient } from "@angular/common/http";
|
import { HttpClient } from "@angular/common/http";
|
||||||
import { Injectable } from "@angular/core";
|
import { Injectable } from "@angular/core";
|
||||||
|
import * as Bowser from "bowser";
|
||||||
|
import { take } from "rxjs/operators";
|
||||||
import { environment } from "src/environments/environment";
|
import { environment } from "src/environments/environment";
|
||||||
import { ClientInfo } from "../_models/client-info";
|
import { ClientInfo } from "../_models/stats/client-info";
|
||||||
|
import { DetailsVersion } from "../_models/stats/details-version";
|
||||||
|
import { NavService } from "./nav.service";
|
||||||
|
import { version } from '../../../package.json';
|
||||||
|
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@ -10,9 +16,27 @@ export class StatsService {
|
|||||||
|
|
||||||
baseUrl = environment.apiUrl;
|
baseUrl = environment.apiUrl;
|
||||||
|
|
||||||
constructor(private httpClient: HttpClient) { }
|
constructor(private httpClient: HttpClient, private navService: NavService) { }
|
||||||
|
|
||||||
public sendClientInfo(clientInfo: ClientInfo) {
|
public async sendClientInfo() {
|
||||||
return this.httpClient.post(this.baseUrl + 'stats/client-info', clientInfo);
|
const data = await this.getInfo();
|
||||||
|
this.httpClient.post(this.baseUrl + 'stats/client-info', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getInfo(): Promise<ClientInfo> {
|
||||||
|
const screenResolution = `${window.screen.width} x ${window.screen.height}`;
|
||||||
|
|
||||||
|
const browser = Bowser.getParser(window.navigator.userAgent);
|
||||||
|
|
||||||
|
const usingDarkTheme = await this.navService.darkMode$.pipe(take(1)).toPromise();
|
||||||
|
|
||||||
|
return {
|
||||||
|
os: browser.getOS() as DetailsVersion,
|
||||||
|
browser: browser.getBrowser() as DetailsVersion,
|
||||||
|
platformType: browser.getPlatformType(),
|
||||||
|
kavitaUiVersion: version,
|
||||||
|
screenResolution,
|
||||||
|
usingDarkTheme
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,7 +5,6 @@ import { take } from 'rxjs/operators';
|
|||||||
import { MemberService } from '../_services/member.service';
|
import { MemberService } from '../_services/member.service';
|
||||||
import { AccountService } from '../_services/account.service';
|
import { AccountService } from '../_services/account.service';
|
||||||
import { StatsService } from '../_services/stats.service';
|
import { StatsService } from '../_services/stats.service';
|
||||||
import * as ClientUtils from "../shared/utils/clientUtils";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-home',
|
selector: 'app-home',
|
||||||
@ -35,9 +34,7 @@ export class HomeComponent implements OnInit {
|
|||||||
|
|
||||||
this.accountService.currentUser$.pipe(take(1)).subscribe(user => {
|
this.accountService.currentUser$.pipe(take(1)).subscribe(user => {
|
||||||
|
|
||||||
this.statsService.sendClientInfo(ClientUtils.getClientInfo())
|
this.statsService.sendClientInfo();
|
||||||
.pipe(take(1))
|
|
||||||
.subscribe(resp => {/* No Operation */});
|
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
this.router.navigateByUrl('/library');
|
this.router.navigateByUrl('/library');
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
.poster {
|
.poster {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
max-height: 230px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rating-star {
|
.rating-star {
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
import * as Bowser from "bowser";
|
|
||||||
import { version } from '../../../../package.json';
|
|
||||||
import { ClientInfo } from "src/app/_models/client-info";
|
|
||||||
import { DetailsVersion } from "src/app/_models/details-version";
|
|
||||||
|
|
||||||
const getClientInfo = (): ClientInfo => {
|
|
||||||
|
|
||||||
const screenResolution = `${window.screen.width} x ${window.screen.height}`;
|
|
||||||
|
|
||||||
const browser = Bowser.getParser(window.navigator.userAgent);
|
|
||||||
|
|
||||||
return {
|
|
||||||
os: browser.getOS() as DetailsVersion,
|
|
||||||
browser: browser.getBrowser() as DetailsVersion,
|
|
||||||
platformType: browser.getPlatformType(),
|
|
||||||
kavitaUiVersion: version,
|
|
||||||
screenResolution
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export { getClientInfo };
|
|
Loading…
x
Reference in New Issue
Block a user