@crazyrabbitltc/railway-mcp
Version:
Railway MCP Server - 146+ tools with 100% Railway API coverage, comprehensive MCP testing framework, and real infrastructure management through AI assistants. Enhanced version with enterprise features, based on original work by Jason Tan.
203 lines (202 loc) • 8.77 kB
JavaScript
import { BaseService } from "./base.service.js";
import { createSuccessResponse, createErrorResponse, formatError } from "../utils/responses.js";
export class LogsService extends BaseService {
constructor() {
super();
}
async getBuildLogs(deploymentId, options = {}) {
try {
const logs = await this.client.logs.getBuildLogs(deploymentId, options.filter, options.limit || 100, options.startDate, options.endDate);
// Format logs for better readability
const formattedLogs = logs.map(log => ({
timestamp: log.timestamp,
level: log.severity || 'INFO',
message: log.message,
...(log.attributes && { attributes: log.attributes }),
...(log.tags && log.tags.length > 0 && { tags: log.tags })
}));
return createSuccessResponse({
text: `Retrieved ${logs.length} build log entries`,
data: {
deploymentId,
logCount: logs.length,
logs: formattedLogs
}
});
}
catch (error) {
return createErrorResponse(`Failed to get build logs: ${formatError(error)}`);
}
}
async getDeploymentLogs(deploymentId, options = {}) {
try {
const logs = await this.client.logs.getDeploymentLogs(deploymentId, options.filter, options.limit || 100, options.startDate, options.endDate);
// Format logs for better readability
const formattedLogs = logs.map(log => ({
timestamp: log.timestamp,
level: log.severity || 'INFO',
message: log.message,
...(log.attributes && { attributes: log.attributes }),
...(log.tags && log.tags.length > 0 && { tags: log.tags })
}));
return createSuccessResponse({
text: `Retrieved ${logs.length} deployment log entries`,
data: {
deploymentId,
logCount: logs.length,
logs: formattedLogs
}
});
}
catch (error) {
return createErrorResponse(`Failed to get deployment logs: ${formatError(error)}`);
}
}
async getEnvironmentLogs(environmentId, options = {}) {
try {
const logs = await this.client.logs.getEnvironmentLogs(environmentId, options.filter, options.limit || 100, options.startDate, options.endDate);
// Format logs for better readability
const formattedLogs = logs.map(log => ({
timestamp: log.timestamp,
level: log.severity || 'INFO',
message: log.message,
...(log.attributes && { attributes: log.attributes }),
...(log.tags && log.tags.length > 0 && { tags: log.tags })
}));
return createSuccessResponse({
text: `Retrieved ${logs.length} environment log entries`,
data: {
environmentId,
logCount: logs.length,
logs: formattedLogs
}
});
}
catch (error) {
return createErrorResponse(`Failed to get environment logs: ${formatError(error)}`);
}
}
async getHttpLogs(deploymentId, options = {}) {
try {
const logs = await this.client.logs.getHttpLogs(deploymentId, options.filter, options.limit || 100, options.startDate, options.endDate);
// Format HTTP logs with relevant metrics
const formattedLogs = logs.map(log => ({
timestamp: log.timestamp,
request: {
method: log.method,
path: log.path,
host: log.host,
userAgent: log.clientUa,
sourceIp: log.srcIp
},
response: {
status: log.httpStatus,
duration: `${log.totalDuration}ms`,
details: log.responseDetails
},
network: {
bytesReceived: log.rxBytes,
bytesSent: log.txBytes,
edgeRegion: log.edgeRegion,
upstreamDuration: log.upstreamRqDuration ? `${log.upstreamRqDuration}ms` : undefined
},
requestId: log.requestId
}));
// Calculate summary statistics
const stats = {
totalRequests: logs.length,
avgDuration: logs.length > 0
? Math.round(logs.reduce((sum, log) => sum + log.totalDuration, 0) / logs.length)
: 0,
statusCodes: logs.reduce((acc, log) => {
const statusGroup = `${Math.floor(log.httpStatus / 100)}xx`;
acc[statusGroup] = (acc[statusGroup] || 0) + 1;
return acc;
}, {}),
totalBytesReceived: logs.reduce((sum, log) => sum + log.rxBytes, 0),
totalBytesSent: logs.reduce((sum, log) => sum + log.txBytes, 0)
};
return createSuccessResponse({
text: `Retrieved ${logs.length} HTTP log entries`,
data: {
deploymentId,
logCount: logs.length,
stats,
logs: formattedLogs
}
});
}
catch (error) {
return createErrorResponse(`Failed to get HTTP logs: ${formatError(error)}`);
}
}
async getMetrics(options) {
try {
const metrics = await this.client.logs.getMetrics(options.startDate, options.measurements, options.groupBy, {
endDate: options.endDate,
projectId: options.projectId,
environmentId: options.environmentId,
serviceId: options.serviceId,
deploymentId: options.deploymentId,
sampleRateSeconds: options.sampleRateSeconds
});
// Format metrics for better readability
const formattedMetrics = metrics.map(metric => {
// Calculate statistics for each metric
const values = metric.values || [];
const stats = values.length > 0 ? {
min: Math.min(...values.map(v => v.value)),
max: Math.max(...values.map(v => v.value)),
avg: values.reduce((sum, v) => sum + v.value, 0) / values.length,
latest: values[values.length - 1]?.value
} : null;
return {
measurement: metric.measurement,
tags: metric.tags,
dataPoints: values.length,
stats,
values: values.slice(-10) // Return last 10 data points
};
});
return createSuccessResponse({
text: `Retrieved metrics for ${options.measurements.length} measurement(s)`,
data: {
timeRange: {
start: options.startDate,
end: options.endDate || 'now'
},
metrics: formattedMetrics
}
});
}
catch (error) {
return createErrorResponse(`Failed to get metrics: ${formatError(error)}`);
}
}
async getPluginLogs(pluginId, environmentId, options = {}) {
try {
const logs = await this.client.logs.getPluginLogs(pluginId, environmentId, options.filter, options.limit || 100, options.startDate, options.endDate);
// Format logs for better readability
const formattedLogs = logs.map(log => ({
timestamp: log.timestamp,
level: log.severity || 'INFO',
message: log.message,
...(log.attributes && { attributes: log.attributes }),
...(log.tags && log.tags.length > 0 && { tags: log.tags })
}));
return createSuccessResponse({
text: `Retrieved ${logs.length} plugin log entries`,
data: {
pluginId,
environmentId,
logCount: logs.length,
logs: formattedLogs
}
});
}
catch (error) {
return createErrorResponse(`Failed to get plugin logs: ${formatError(error)}`);
}
}
}
export const logsService = new LogsService();