diff --git a/Cargo.toml b/Cargo.toml
index 6dd72991..6d828269 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,6 +29,8 @@ with_failure = ["failure", "with_backtrace"]
 with_log = ["log", "with_backtrace"]
 with_debug_to_log = ["log"]
 with_env_logger = ["with_log", "env_logger"]
+with_slog = ["slog", "serde_json"]
+with_slog_nested = ["with_slog", "slog/nested-values"]
 with_error_chain = ["error-chain", "with_backtrace"]
 with_device_info = ["libc", "hostname", "uname", "with_client_implementation"]
 with_rust_info = ["rustc_version", "with_client_implementation"]
@@ -44,6 +46,7 @@ failure = { version = "0.1.6", optional = true }
 log = { version = "0.4.8", optional = true, features = ["std"] }
 sentry-types = "0.14.1"
 env_logger = { version = "0.7.1", optional = true }
+slog = { version = "2.5.2", optional = true, default-features = false }
 reqwest = { version = "0.10.1", optional = true, features = ["blocking", "json"], default-features = false }
 lazy_static = "1.4.0"
 regex = { version = "1.3.4", optional = true }
@@ -80,5 +83,9 @@ required-features = ["with_env_logger"]
 name = "thread-demo"
 required-features = ["with_env_logger"]
 
+[[example]]
+name = "slog-demo"
+required-features = ["with_slog_nested"]
+
 [workspace]
 members = [".", "integrations/sentry-actix"]
diff --git a/examples/slog-demo.rs b/examples/slog-demo.rs
new file mode 100644
index 00000000..26df1093
--- /dev/null
+++ b/examples/slog-demo.rs
@@ -0,0 +1,20 @@
+use slog::{debug, error, info, warn};
+
+fn main() {
+    let drain = slog::Discard;
+    // Default options - breadcrumb from info, event from warnings
+    let wrapped_drain = sentry::integrations::slog::wrap_drain(drain, Default::default());
+    let _sentry = sentry::init((
+        "https://a94ae32be2584e0bbd7a4cbb95971fee@sentry.io/1041156",
+        sentry::ClientOptions {
+            release: sentry::release_name!(),
+            ..Default::default()
+        },
+    ));
+    let root = slog::Logger::root(wrapped_drain, slog::o!("test_slog" => 0));
+
+    debug!(root, "This should not appear"; "111" => "222");
+    info!(root, "Info breadcrumb"; "222" => 333);
+    warn!(root, "Warning event"; "333" => true);
+    error!(root, "Error event"; "444" => "555");
+}
diff --git a/src/integrations/mod.rs b/src/integrations/mod.rs
index 0ba2709c..737861a1 100644
--- a/src/integrations/mod.rs
+++ b/src/integrations/mod.rs
@@ -13,5 +13,8 @@ pub mod log;
 #[cfg(feature = "with_env_logger")]
 pub mod env_logger;
 
+#[cfg(feature = "with_slog")]
+pub mod slog;
+
 #[cfg(feature = "with_panic")]
 pub mod panic;
diff --git a/src/integrations/slog.rs b/src/integrations/slog.rs
new file mode 100644
index 00000000..54e630a8
--- /dev/null
+++ b/src/integrations/slog.rs
@@ -0,0 +1,287 @@
+//! Adds support for automatic breadcrumb capturing from logs with `slog`.
+//!
+//! **Feature:** `with_slog` + `with_slog_nested` (optional)
+//!
+//! # Configuration
+//!
+//! In the most trivial version you could proceed like this:
+//!
+//! ```no_run
+//! # extern crate slog;
+//!
+//! let drain = slog::Discard;
+//! let wrapped_drain = sentry::integrations::slog::wrap_drain(drain, Default::default());
+//! let root = slog::Logger::root(drain, slog::o!());
+//!
+//! slog::warn!(root, "Log for sentry")
+//! ```
+use slog::{Drain, Serializer, KV};
+use std::{collections::BTreeMap, fmt};
+
+use crate::{
+    api::add_breadcrumb,
+    hub::Hub,
+    protocol::{Breadcrumb, Event},
+    with_scope, Level,
+};
+
+// Serializer which stores the serde_json values in BTreeMap
+struct StoringSerializer {
+    result: BTreeMap<String, serde_json::Value>,
+}
+
+impl StoringSerializer {
+    #[allow(missing_docs)]
+    fn emit_serde_json_value(&mut self, key: slog::Key, val: serde_json::Value) -> slog::Result {
+        self.result.insert(key.to_string(), val);
+        Ok(())
+    }
+
+    #[allow(missing_docs)]
+    fn emit_serde_json_null(&mut self, key: slog::Key) -> slog::Result {
+        self.emit_serde_json_value(key, serde_json::Value::Null)
+    }
+
+    #[allow(missing_docs)]
+    fn emit_serde_json_bool(&mut self, key: slog::Key, val: bool) -> slog::Result {
+        self.emit_serde_json_value(key, serde_json::Value::Bool(val))
+    }
+
+    #[allow(missing_docs)]
+    fn emit_serde_json_number<V>(&mut self, key: slog::Key, value: V) -> slog::Result
+    where
+        serde_json::Number: From<V>,
+    {
+        let num = serde_json::Number::from(value);
+        self.emit_serde_json_value(key, serde_json::Value::Number(num))
+    }
+
+    #[allow(missing_docs)]
+    fn emit_serde_json_string(&mut self, key: slog::Key, val: String) -> slog::Result {
+        self.emit_serde_json_value(key, serde_json::Value::String(val))
+    }
+}
+
+macro_rules! impl_number {
+    ( $type:ty => $function_name:ident ) => {
+        #[allow(missing_docs)]
+        fn $function_name(&mut self, key: slog::Key, val: $type) -> slog::Result {
+            self.emit_serde_json_number(key, val)
+        }
+    };
+}
+
+impl Serializer for StoringSerializer {
+    #[allow(missing_docs)]
+    fn emit_bool(&mut self, key: slog::Key, val: bool) -> slog::Result {
+        self.emit_serde_json_bool(key, val)
+    }
+
+    #[allow(missing_docs)]
+    fn emit_unit(&mut self, key: slog::Key) -> slog::Result {
+        self.emit_serde_json_null(key)
+    }
+
+    #[allow(missing_docs)]
+    fn emit_none(&mut self, key: slog::Key) -> slog::Result {
+        self.emit_serde_json_null(key)
+    }
+
+    #[allow(missing_docs)]
+    fn emit_char(&mut self, key: slog::Key, val: char) -> slog::Result {
+        self.emit_serde_json_string(key, val.to_string())
+    }
+
+    #[allow(missing_docs)]
+    fn emit_str(&mut self, key: slog::Key, val: &str) -> slog::Result {
+        self.emit_serde_json_string(key, val.to_string())
+    }
+
+    #[allow(missing_docs)]
+    fn emit_f64(&mut self, key: slog::Key, val: f64) -> slog::Result {
+        if let Some(num) = serde_json::Number::from_f64(val) {
+            self.emit_serde_json_value(key, serde_json::Value::Number(num))
+        } else {
+            self.emit_serde_json_null(key)
+        }
+    }
+
+    impl_number!(u8 => emit_u8);
+    impl_number!(i8 => emit_i8);
+    impl_number!(u16 => emit_u16);
+    impl_number!(i16 => emit_i16);
+    impl_number!(u32 => emit_u32);
+    impl_number!(i32 => emit_i32);
+    impl_number!(u64 => emit_u64);
+    impl_number!(i64 => emit_i64);
+
+    // u128 and i128 should be implemented in serde_json 1.0.40
+    // impl_number!(u128 => emit_u128);
+    // impl_number!(i128 => emit_i128);
+
+    #[cfg(feature = "with_slog_nested")]
+    #[allow(missing_docs)]
+    fn emit_serde(&mut self, key: slog::Key, value: &dyn slog::SerdeValue) -> slog::Result {
+        self.emit_serde_json_value(key, serde_json::json!(value.as_serde()))
+    }
+
+    #[allow(missing_docs)]
+    fn emit_arguments(&mut self, _: slog::Key, _: &fmt::Arguments) -> slog::Result {
+        Ok(())
+    }
+}
+
+/// Converts `slog::Level` to `Level`
+fn into_sentry_level(slog_level: slog::Level) -> Level {
+    match slog_level {
+        slog::Level::Trace | slog::Level::Debug => Level::Debug,
+        slog::Level::Info => Level::Info,
+        slog::Level::Warning => Level::Warning,
+        slog::Level::Error | slog::Level::Critical => Level::Error,
+    }
+}
+
+/// Options for the slog configuration
+#[derive(Debug, Copy, Clone)]
+pub struct Options {
+    /// Level since when the breadcrumbs are created
+    breadcrumb_level: slog::Level,
+    /// Level since when the events are sent
+    event_level: slog::Level,
+}
+
+impl Options {
+    /// Creates new slog integration options
+    pub fn new(breadcrumb_level: slog::Level, event_level: slog::Level) -> Self {
+        Self {
+            breadcrumb_level,
+            event_level,
+        }
+    }
+}
+
+impl Default for Options {
+    fn default() -> Self {
+        Self {
+            breadcrumb_level: slog::Level::Info,
+            event_level: slog::Level::Warning,
+        }
+    }
+}
+
+/// Wrapped drain for sentry logging
+#[derive(Debug, Copy, Clone)]
+pub struct WrappedDrain<D>
+where
+    D: Drain,
+{
+    drain: D,
+    options: Options,
+}
+
+fn get_record_data(record: &slog::Record) -> BTreeMap<String, serde_json::Value> {
+    let mut storing_serializer = StoringSerializer {
+        result: BTreeMap::new(),
+    };
+
+    // slog::KV can be only serialized, but we need to obtain its data
+    // To do that a Serializer was implemented to store these data to a dict
+    if record
+        .kv()
+        .serialize(record, &mut storing_serializer)
+        .is_ok()
+    {
+        storing_serializer.result
+    } else {
+        BTreeMap::new()
+    }
+}
+
+impl<D> WrappedDrain<D>
+where
+    D: Drain,
+{
+    /// Creates a new wrapped Drain
+    fn new(drain: D, options: Options) -> Self {
+        Self { drain, options }
+    }
+
+    /// Creates a breadcrumb
+    fn add_breadcrumb(record: &slog::Record) {
+        let data = get_record_data(record);
+
+        let breadcrumb = Breadcrumb {
+            message: Some(record.msg().to_string()),
+            level: into_sentry_level(record.level()),
+            data,
+            ..Breadcrumb::default()
+        };
+        add_breadcrumb(|| breadcrumb);
+    }
+
+    /// Captures an event
+    fn capture_event(record: &slog::Record) {
+        let extra = get_record_data(record);
+
+        let event = Event {
+            message: Some(record.msg().to_string()),
+            level: into_sentry_level(record.level()),
+            ..Event::default()
+        };
+
+        with_scope(
+            |scope| {
+                for (key, value) in extra {
+                    scope.set_extra(&key, value);
+                }
+            },
+            || {
+                Hub::with_active(move |hub| hub.capture_event(event));
+            },
+        );
+    }
+}
+
+impl<D> Drain for WrappedDrain<D>
+where
+    D: Drain,
+{
+    type Ok = D::Ok;
+    type Err = D::Err;
+
+    fn log(
+        &self,
+        record: &slog::Record,
+        values: &slog::OwnedKVList,
+    ) -> Result<Self::Ok, Self::Err> {
+        let level = record.level();
+        if level <= self.options.event_level {
+            // log event
+            Self::capture_event(record);
+        } else if level <= self.options.breadcrumb_level {
+            // or log bread crumbs
+            Self::add_breadcrumb(record);
+        }
+
+        self.drain.log(record, values)
+    }
+}
+
+impl<D> std::ops::Deref for WrappedDrain<D>
+where
+    D: Drain,
+{
+    type Target = D;
+
+    fn deref(&self) -> &Self::Target {
+        &self.drain
+    }
+}
+
+/// Wraps `slog::Drain`
+pub fn wrap_drain<D>(drain: D, options: Options) -> WrappedDrain<D>
+where
+    D: slog::Drain,
+{
+    WrappedDrain::new(drain, options)
+}
diff --git a/src/lib.rs b/src/lib.rs
index f8f7cbed..70ba70e3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -105,6 +105,8 @@
 //! * `with_rustls`: Enables the `rustls` TLS implementation.  This is currently the default when
 //!   using the `with_reqwest_transport` feature.
 //! * `with_native_tls`: Enables the `default-tls` feature of the `reqwest` library.
+//! * `with_slog`: enables the `slog` integration
+//! * `with_slog_nested`: enables the `slog` integration with nested feature compiled
 //!
 //! Testing:
 //!