Repository: ReactiveX/RxSwift
File: RxSwift/ObservableType+Extensions.swift (Swift)

Code before:
                }
            }
            return Disposables.create(
                self.asObservable().subscribe(observer),
                disposable
            )
    }
}

import class Foundation.NSRecursiveLock

extension Hooks {
    public typealias DefaultErrorHandler = (_ subscriptionCallStack: [String], _ error: Error) -> ()
    public typealias SubscriptionCallstackGenerationHandler = () -> [String]

    fileprivate static let _lock = RecursiveLock()
    fileprivate static let _subscriptionCallstackLock = RecursiveLock()
    fileprivate static var _defaultErrorHandler: DefaultErrorHandler = { subscriptionCallStack, error in
        #if DEBUG
            let serializedCallStack = subscriptionCallStack.joined(separator: "\n")
            print("Unhandled error happened: \(error)\n subscription called from:\n\(serializedCallStack)")
        #endif
    }
    fileprivate static var _subscriptionCallstackGenerationHandler: SubscriptionCallstackGenerationHandler = {
        #if DEBUG
            return Hooks.recordCallStackOnError ? Thread.callStackSymbols : []
        #else
            return []
        #endif
    }

    /// Error handler called in case onError handler wasn't provided.
    public static var defaultErrorHandler: DefaultErrorHandler {
        get {
            _lock.lock(); defer { _lock.unlock() }
            return _defaultErrorHandler
        }
        set {
            _lock.lock(); defer { _lock.unlock() }
            _defaultErrorHandler = newValue
        }
    }
    
    /// Subscription callstack handler to fetch custom callstack information.
    public static var subscriptionCallstackGenerationHandler: SubscriptionCallstackGenerationHandler {
        get {
            _subscriptionCallstackLock.lock(); defer { _subscriptionCallstackLock.unlock() }
            return _subscriptionCallstackGenerationHandler
        }
        set {
            _subscriptionCallstackLock.lock(); defer { _subscriptionCallstackLock.unlock() }

Review comment (bug):
This seems like a wrong logic. According to name `Hooks.recordCallStackOnError` should control should callstack be recorded and override both default `Thread.callStackSymbols` and custom logic.

I would probably make this `fileprivate static var _callstackCapturer = Thread.callStackSymbols`, and then 

```
#if DEBUG
let callStack = Hooks.recordCallStackOnError ? Hooks.subscriptionCallstackGenerationHandler() : []
#else
let callStack = []
#endif

Code after:
                }
            }
            return Disposables.create(
                self.asObservable().subscribe(observer),
                disposable
            )
    }
}

import class Foundation.NSRecursiveLock

extension Hooks {
    public typealias DefaultErrorHandler = (_ subscriptionCallStack: [String], _ error: Error) -> ()
    public typealias CustomCaptureSubscriptionCallstack = () -> [String]

    fileprivate static let _lock = RecursiveLock()
    fileprivate static var _defaultErrorHandler: DefaultErrorHandler = { subscriptionCallStack, error in
        #if DEBUG
            let serializedCallStack = subscriptionCallStack.joined(separator: "\n")
            print("Unhandled error happened: \(error)\n subscription called from:\n\(serializedCallStack)")
        #endif
    }
    fileprivate static var _customCaptureSubscriptionCallstack: CustomCaptureSubscriptionCallstack = {
        #if DEBUG
            return Thread.callStackSymbols
        #else
            return []
        #endif
    }

    /// Error handler called in case onError handler wasn't provided.
    public static var defaultErrorHandler: DefaultErrorHandler {
        get {
            _lock.lock(); defer { _lock.unlock() }
            return _defaultErrorHandler
        }
        set {
            _lock.lock(); defer { _lock.unlock() }
            _defaultErrorHandler = newValue
        }
    }
    
    /// Subscription callstack block to fetch custom callstack information.
    public static var customCaptureSubscriptionCallstack: CustomCaptureSubscriptionCallstack {
        get {
            _lock.lock(); defer { _lock.unlock() }
            return _customCaptureSubscriptionCallstack
        }
        set {
            _lock.lock(); defer { _lock.unlock() }
            _customCaptureSubscriptionCallstack = newValue