草庐IT

swift - 用于日志记录的 SQLite 跟踪

coder 2023-09-09 原文

我正在尝试使用 tracing 在我的代码中调试一些 SQLite 查询只需将发生的一切记录到控制台,但似乎几乎没有任何信息——谷歌搜索“sqlite3_trace_v2 swift”只返回两页结果,除了上面的链接外,没有任何帮助。使用以下代码,我能够让它至少运行跟踪回调:

func traceSQL (database: OpaquePointer?) {
    var pointer: OpaquePointer?
    func traceCallback (mask: UInt32, pointer: UnsafeMutableRawPointer?, query: UnsafeMutableRawPointer?, result: UnsafeMutableRawPointer?) -> Int32 {
        print("SQLite Trace:")

        if let query = query?.load(as: UnsafePointer<Int8>.self) {
            print(String(cString: query))
        } else {
            print("Could not load query.")
        }

        if let result = result?.load(as: UnsafePointer<Int8>.self) {
            print(String(cString: result))
        } else {
            print("Could not load result.")
        }

        return 0
    }
    sqlite3_trace_v2(database, 15, traceCallback as @convention(c) (UInt32, UnsafeMutableRawPointer?, UnsafeMutableRawPointer?, UnsafeMutableRawPointer?) -> Int32, &pointer)
}

但我无法弄清楚如何处理该函数的输出 - 目前,它只是打印出一串不可读的字符,而我之前的尝试甚至没有做到这一点。我怀疑至少部分问题是我真的不知道如何在 Swift 中使用 UnsafeMutableRawPointer(可用信息中似乎缺少其他东西)。

tl;dr:如何记录来自 SQLite 的跟踪结果?

最佳答案

您代码中的主要错误是您取消引用 原始指针 传递给回调而不是重新解释(转换)它们。 这些指针的含义对于不同的人也是不同的 事件。

下面是一个如何跟踪各种事件以及如何转换的例子 使用文字闭包指向“正确”类型的原始指针 作为回调。解释 px 含义的注释 参数取自 SQL Trace Event Codes .

let traceMask = SQLITE_TRACE_STMT|SQLITE_TRACE_PROFILE|SQLITE_TRACE_ROW|SQLITE_TRACE_CLOSE

sqlite3_trace_v2(database, UInt32(traceMask), { (reason, context, p, x) -> Int32 in
    switch Int32(reason) {
    case SQLITE_TRACE_STMT:
        // The P argument is a pointer to the prepared statement.
        // The X argument is a pointer to a string which is the unexpanded SQL text 
        guard
            let pStmt = OpaquePointer(p),
            let cSql = x?.assumingMemoryBound(to: CChar.self)
        else {
            return 0
        }

        let sql = String(cString: cSql) // The unexpanded SQL text
        let expandedSql = String(cString: sqlite3_expanded_sql(pStmt)) // The expanded SQL text
        print("SQLITE_TRACE_STMT:", expandedSql)

    case SQLITE_TRACE_PROFILE:
        // The P argument is a pointer to the prepared statement and the X argument points
        // to a 64-bit integer which is the estimated of the number of nanosecond that the
        // prepared statement took to run.
        guard
            let pStmt = OpaquePointer(p),
            let duration = x?.load(as: UInt64.self)
        else {
            return 0
        }

        let milliSeconds = Double(duration)/Double(NSEC_PER_MSEC)
        let sql = String(cString: sqlite3_sql(pStmt)) // The unexpanded SQL text
        print("SQLITE_TRACE_PROFILE:", milliSeconds, "ms for statement:", sql)

    case SQLITE_TRACE_ROW:
        // The P argument is a pointer to the prepared statement and the X argument is unused.
        guard
            let pStmt = OpaquePointer(p)
        else {
            return 0
        }

        print("SQLITE_TRACE_ROW")

    case SQLITE_TRACE_CLOSE:
        // The P argument is a pointer to the database connection object and the X argument is unused.
        guard
            let database = OpaquePointer(p)
        else {
            return 0
        }

        print("SQLITE_TRACE_CLOSE")

    default:
        break
    }
    return 0
}, nil)

当然,您可以将跟踪模式限制为您所关注的事件 很有趣,例如

let traceMask = SQLITE_TRACE_STMT

仅跟踪准备好的语句。

关于swift - 用于日志记录的 SQLite 跟踪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43593618/

有关swift - 用于日志记录的 SQLite 跟踪的更多相关文章

  1. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  2. ruby - Sinatra:运行 rspec 测试时记录噪音 - 2

    Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/

  3. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  4. ruby-on-rails - Rails 5 Active Record 记录无效错误 - 2

    我有两个Rails模型,即Invoice和Invoice_details。一个Invoice_details属于Invoice,一个Invoice有多个Invoice_details。我无法使用accepts_nested_attributes_forinInvoice通过Invoice模型保存Invoice_details。我收到以下错误:(0.2ms)BEGIN(0.2ms)ROLLBACKCompleted422UnprocessableEntityin25ms(ActiveRecord:4.0ms)ActiveRecord::RecordInvalid(Validationfa

  5. ruby - inverse_of 是否适用于 has_many? - 2

    当我使用has_one时,它​​工作得很好,但在has_many上却不行。在这里您可以看到object_id不同,因为它运行了另一个SQL来再次获取它。ruby-1.9.2-p290:001>e=Employee.create(name:'rafael',active:false)ruby-1.9.2-p290:002>b=Badge.create(number:1,employee:e)ruby-1.9.2-p290:003>a=Address.create(street:"123MarketSt",city:"SanDiego",employee:e)ruby-1.9.2-p290

  6. ruby-on-rails - 事件记录 : Select max of limit - 2

    我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

  7. Ruby 守护进程导致 ActiveRecord 记录器 IOError - 2

    我目前正在用Ruby编写一个项目,它使用ActiveRecordgem进行数据库交互,我正在尝试使用ActiveRecord::Base.logger记录所有数据库事件具有以下代码的属性ActiveRecord::Base.logger=Logger.new(File.open('logs/database.log','a'))这适用于迁移等(出于某种原因似乎需要启用日志记录,因为它在禁用时会出现NilClass错误)但是当我尝试运行包含调用ActiveRecord对象的线程守护程序的项目时脚本失败并出现以下错误/System/Library/Frameworks/Ruby.frame

  8. ruby-on-rails - 在 Rails 中更高效地查找或创建多条记录 - 2

    我有一个应用需要发送用户事件邀请。当用户邀请friend(用户)参加事件时,如果尚不存在将用户连接到该事件的新记录,则会创建该记录。我的模型由用户、事件和events_user组成。classEventdefinvite(user_id,*args)user_id.eachdo|u|e=EventsUser.find_or_create_by_event_id_and_user_id(self.id,u)e.save!endendend用法Event.first.invite([1,2,3])我不认为以上是完成我的任务的最有效方法。我设想了一种方法,例如Model.find_or_cr

  9. ruby - "undefined method"用于 rails 模型 - 2

    我正在使用带有Rails的Devise,我想添加一个方法“getAllComments”,所以我这样写:classUser在我的Controller中:defdashboard@user=current_user@comments=@user.getAllComments();end当我访问我的url时,我得到了undefinedmethod`getAllComments'for#我做错了什么?谢谢 最佳答案 因为getAllComments是一个类方法,而您正试图将其作为实例方法访问。您要么需要访问它:User.getAllCom

  10. Ruby on Rails regexp equals-tilde 与 array include 用于检查选项列表 - 2

    我正在使用Rails3.2.3和Ruby1.9.3p0。我发现我经常需要确定某个字符串是否出现在选项列表中。看来我可以使用Ruby数组.includemethod:或正则表达式equals-tildematchshorthand用竖线分隔选项:就性能而言,一个比另一个好吗?还有更好的方法吗? 最佳答案 总结:Array#include?包含String元素,在接受和拒绝输入时均胜出,对于您的示例只有三个可接受的值。对于要检查的更大的集合,看起来Set#include?和String元素可能会获胜。如何测试我们应该根据经验对此进行测试

随机推荐