Skip to main content

crates_docs/
lib.rs

1//! Crates Docs MCP Server
2//!
3//! A high-performance Rust crate documentation query MCP server with support for multiple transport protocols and OAuth authentication.
4
5#![warn(missing_docs)]
6#![warn(clippy::pedantic)]
7#![allow(clippy::module_name_repetitions)]
8#![allow(clippy::missing_errors_doc)]
9#![allow(clippy::missing_panics_doc)]
10
11pub mod cache;
12pub mod config;
13pub mod error;
14pub mod server;
15pub mod tools;
16pub mod utils;
17
18/// Re-export common types
19pub use crate::error::{Error, Result};
20pub use crate::server::{CratesDocsServer, ServerConfig};
21
22/// Server version information
23pub const VERSION: &str = env!("CARGO_PKG_VERSION");
24
25/// Server name
26pub const NAME: &str = "crates-docs";
27
28/// Initialize the logging system (simple version using boolean parameter)
29///
30/// # Errors
31/// Returns an error if logging system initialization fails
32#[deprecated(note = "Please use init_logging_with_config instead")]
33pub fn init_logging(debug: bool) -> Result<()> {
34    use tracing_subscriber::{fmt, prelude::*, EnvFilter};
35
36    let filter = if debug {
37        EnvFilter::new("debug")
38    } else {
39        EnvFilter::new("info")
40    };
41
42    let fmt_layer = fmt::layer()
43        .with_target(true)
44        .with_thread_ids(true)
45        .with_thread_names(true)
46        .compact();
47
48    tracing_subscriber::registry()
49        .with(filter)
50        .with(fmt_layer)
51        .try_init()
52        .map_err(|e| error::Error::Initialization(e.to_string()))?;
53
54    Ok(())
55}
56
57/// Initialize logging system with configuration
58///
59/// # Errors
60/// Returns an error if logging system initialization fails
61pub fn init_logging_with_config(config: &crate::config::LoggingConfig) -> Result<()> {
62    use tracing_subscriber::{fmt, prelude::*, EnvFilter};
63
64    // Parse log level
65    let level = match config.level.to_lowercase().as_str() {
66        "trace" => "trace",
67        "debug" => "debug",
68        "warn" => "warn",
69        "error" => "error",
70        _ => "info",
71    };
72
73    let filter = EnvFilter::new(level);
74
75    // Build log layers based on configuration
76    match (config.enable_console, config.enable_file, &config.file_path) {
77        // Enable both console and file logging
78        (true, true, Some(file_path)) => {
79            // Determine log directory
80            let log_dir = std::path::Path::new(file_path)
81                .parent()
82                .filter(|p| !p.as_os_str().is_empty())
83                .unwrap_or_else(|| std::path::Path::new("."));
84            let log_file_name = std::path::Path::new(file_path)
85                .file_name()
86                .unwrap_or(std::ffi::OsStr::new("crates-docs.log"));
87
88            // Ensure directory exists
89            std::fs::create_dir_all(log_dir).map_err(|e| {
90                error::Error::Initialization(format!("Failed to create log directory: {e}"))
91            })?;
92
93            // Create file log layer
94            let file_appender = tracing_appender::rolling::daily(log_dir, log_file_name);
95
96            tracing_subscriber::registry()
97                .with(filter)
98                .with(
99                    fmt::layer()
100                        .with_target(true)
101                        .with_thread_ids(true)
102                        .with_thread_names(true)
103                        .compact(),
104                )
105                .with(
106                    fmt::layer()
107                        .with_writer(file_appender)
108                        .with_target(true)
109                        .with_thread_ids(true)
110                        .with_thread_names(true)
111                        .compact(),
112                )
113                .try_init()
114                .map_err(|e| error::Error::Initialization(e.to_string()))?;
115        }
116
117        // Enable console logging only
118        (true, _, _) | (false, false, _) => {
119            tracing_subscriber::registry()
120                .with(filter)
121                .with(
122                    fmt::layer()
123                        .with_target(true)
124                        .with_thread_ids(true)
125                        .with_thread_names(true)
126                        .compact(),
127                )
128                .try_init()
129                .map_err(|e| error::Error::Initialization(e.to_string()))?;
130        }
131
132        // Enable file logging only
133        (false, true, Some(file_path)) => {
134            // Determine log directory
135            let log_dir = std::path::Path::new(file_path)
136                .parent()
137                .filter(|p| !p.as_os_str().is_empty())
138                .unwrap_or_else(|| std::path::Path::new("."));
139            let log_file_name = std::path::Path::new(file_path)
140                .file_name()
141                .unwrap_or(std::ffi::OsStr::new("crates-docs.log"));
142
143            // Ensure directory exists
144            std::fs::create_dir_all(log_dir).map_err(|e| {
145                error::Error::Initialization(format!("Failed to create log directory: {e}"))
146            })?;
147
148            // Create file log layer
149            let file_appender = tracing_appender::rolling::daily(log_dir, log_file_name);
150
151            tracing_subscriber::registry()
152                .with(filter)
153                .with(
154                    fmt::layer()
155                        .with_writer(file_appender)
156                        .with_target(true)
157                        .with_thread_ids(true)
158                        .with_thread_names(true)
159                        .compact(),
160                )
161                .try_init()
162                .map_err(|e| error::Error::Initialization(e.to_string()))?;
163        }
164
165        // Other cases, use default console logging
166        _ => {
167            tracing_subscriber::registry()
168                .with(filter)
169                .with(
170                    fmt::layer()
171                        .with_target(true)
172                        .with_thread_ids(true)
173                        .with_thread_names(true)
174                        .compact(),
175                )
176                .try_init()
177                .map_err(|e| error::Error::Initialization(e.to_string()))?;
178        }
179    }
180
181    Ok(())
182}