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