{"id":13536396,"url":"https://github.com/luofei614/SocketLog","last_synced_at":"2025-04-02T03:30:36.504Z","repository":{"id":13899161,"uuid":"16597686","full_name":"luofei614/SocketLog","owner":"luofei614","description":"微信调试、API调试和AJAX的调试的工具，能将日志通过WebSocket输出到Chrome浏览器的console中","archived":false,"fork":false,"pushed_at":"2021-03-19T02:55:06.000Z","size":1278,"stargazers_count":1124,"open_issues_count":32,"forks_count":299,"subscribers_count":99,"default_branch":"master","last_synced_at":"2025-03-31T13:05:14.482Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/luofei614.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-02-06T23:15:48.000Z","updated_at":"2025-01-17T18:47:18.000Z","dependencies_parsed_at":"2022-09-01T15:23:04.992Z","dependency_job_id":null,"html_url":"https://github.com/luofei614/SocketLog","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luofei614%2FSocketLog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luofei614%2FSocketLog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luofei614%2FSocketLog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luofei614%2FSocketLog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/luofei614","download_url":"https://codeload.github.com/luofei614/SocketLog/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246750776,"owners_count":20827781,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T09:00:38.439Z","updated_at":"2025-04-02T03:30:36.487Z","avatar_url":"https://github.com/luofei614.png","language":"PHP","funding_links":[],"categories":["PHP","类库"],"sub_categories":["未归类"],"readme":"\n## 一，简介\n\nSocketLog 是一款高效的、探针式的服务器端程序调试和分析工具。\n\n将“探针”引入到目标项目后，SocketLog 会通过在服务端启动的一个 WebSocket 服务，将程序执行过程中收集到的调试信息推送到客户端。\n客户端会通过一个 Chrome 插件将调试信息打印到浏览器的 Console 中，这些信息包括程序的运行时间、吞吐率、内存消耗；PHP 的 Error、warning、notice 信息；程序执行的 SQL 语句以及对 SQL 语句的 explain 等等。\n\nSocketLog 使用 PHP 和 NodeJs 开发，是 FirePHP 和 ChromePHP 的替代者，特别适合用于调试 Ajax 方式发起的请求和 API 项目。\n\n### 1、使用场景举例：\n**用 SocketLog 来做微信开发调试。**\n\n举一个常见的场景：你在做微信 API 开发的时候，是否遇到了 API 有 bug，微信只提示“该公众账号暂时无法提供服务，请稍候再试” ？\n\n我们根本不知道 API 出了什么问题，由于不能打印信息，只能通过日志来排查，这种方式的调试效率实在是太低了。\n\n现在有了 SocketLog 就不一样了，我们可以知道微信给 API 传递了哪些参数，程序有错误我们也能看见错误信息。\n\n![微信调试](./screenshots/weixin.png)\n\n### 2、SocketLog 的用途：\n- **API bug 调试**\n    - 正在运行的 API 有 bug，不能使用 var_dump() 进行调试，因为会影响 client 的调用。\n    将日志写到文件，查看也不方便，特别是带调用栈或大数据结构的文件日志，查看起来十分困难。\n    - 是时候让 SocketLog 大显身手了，它通过 WebSocket 将调试日志打印到浏览器的 Console 中，查看起来非常方便。\n\n- **其他用途**\n    - 你还可以用它来分析开源程序、分析 SQL 性能、结合 PHP Taint 分析程序漏洞。\n\n### 3、文件和目录简要说明：\n```\n├── chrome        ：Chrome 插件的源代码目录。\n├── chrome.crx    ：Chrome 插件的安装包文件，手动安装方法见下文。\n├── demo.php      : Demo 示例文件。\n├── Dockerfile\n├── composer.json\n├── README.md\n├── php\n│   ├── slog.function.php ：探针文件，在需要发送日志的时候，载入这个文件，然后调用其中的函数 slog() 即可。\n│   └── slog.php          ：收集调试日志的函数类库文件，需要在探针文件中载入这个类库。\n├── screenshots           ：README.md 本文档中需要的示例图片。\n└── server\n    ├── bin\n    │   └── socketlog-server：当前目录下启动 WebSocket 服务的文件。\n    ├── config.json\n    ├── index.html          : 申请 client_id 的页面。\n    ├── index.js            ：WebSocket 服务的入口文件。\n    ├── node_modules        ：Node 所需的组件目录。\n    └── package.json\n```\n\n### 4、效果展示：\n针对一个开源的 Web 项目，我们想基于它做二次开发。如果能在浏览网站的时候，可以从浏览器的 Console 中知道程序都做了些什么，这对二次开发将十分有帮助。\n\n下面的效果图显示，在浏览 discuz 程序时，Console 中打印出了：\n- 程序的运行时间、吞吐率和内存消耗信息。\n- 程序的 warning，notice 等错误信息。\n- 当前页面执行了哪些 SQL 语句，以及执行 SQL 语句的调用栈信息。\n\n![打印浏览 discuz 时执行的 SQL 语句](./screenshots/discuz.png)\n\n## 二，安装与使用\n### 1、安装：\n- 1，客户端，安装 Chrome 插件。\n    - 方法一，在线安装：\n\n        打开 [Chrome 网上应用店](https://chrome.google.com/webstore/category/extensions?hl=zh-CN)，搜索 SocketLog ，然后点击 “添加至 Chrome” 完成安装。如果不能正常访问 Chrome 网上应用店，可以尝试如下的手动安装方法。\n\n    - 方法二，手动安装：\n\n        在 GitHub 上下载 [chrome.crx](https://github.com/luofei614/SocketLog)，打开浏览器地址栏并输入：chrome://extensions，将chrome.crx 拖入打开的页面即可。\n- 2，服务端，安装 Socket 服务并启动。\n    \u003e （请确保你的环境已经安装了 NodeJs）\n    - 方法一，npm 方式安装：\n        - 全局安装\n            ```shell\n            $ npm install -g socketlog-server\n            ```\n        - 局部安装 (切换到目标项目所在目录)\n            ```\n            $ npm install socketlog-server\n            ```\n        - 启动服务\n            ```shell\n            ## 普通方式运行：\n            $ socketlog-server\n\n            ## 如果想让服务在后台运行：\n            $ socketlog-server \u003e /dev/null \u0026\n            ```\n    - 方法二，源码方式安装：\n        - 根据实际情况选定目录（例如，在目标项目所在目录下）\n            ```shell\n            ## 下载项目代码或者 clone\n            $ git clone https://github.com/luofei614/SocketLog.git\n            ```\n        - 启动服务\n            ```shell\n            ## 请注意实际项目的 index.js 文件的路径\n            $ node server/index.js\n            ```\n- 3，php 探针文件：\n\n    ```php\n    \u003c?php\n    // 根据实际情况，确定源码的 php 目录放置位置，在需要调试的文件中引入\n    include './php/slog.function.php';\n    slog('hello world');\n    ```\n- 4，说明：\n    - 这样将会在服务器端起一个 WebSocket 服务，监听端口是 1229。\n    - 我们提供公用的服务端，需要去 [申请 client_id](http://slog.thinkphp.cn/) （目前已停服）。\n    - 如果你的服务器有防火墙，请开启 1229 和 1116 两个端口，SocketLog 需要使用它们。\n\n### 2、示例：\n- 1，在自己的程序中发送日志：\n    ```php\n    \u003c?php\n    include './php/slog.function.php';\n    slog('hello world');\n    ```\n- 2，slog() 函数支持的多种日志类型：\n    ```php\n    slog('msg', 'log');    // 一般日志\n    slog('msg', 'error');  // 错误日志\n    slog('msg', 'info');   // 信息日志\n    slog('msg', 'warn');   // 警告日志\n    slog('msg', 'trace');  // 输出日志，同时会打出调用栈\n    slog('msg', 'alert');  // 将日志以alert方式弹出\n    slog('msg', 'log', 'color:red;font-size:20px;'); // 自定义日志的样式，第三个参数为 css 样式\n    ```\n\n- 3，小结：通过上面例子可以看出，slog() 函数支持三个参数：\n    - 第一个参数是 **日志内容**：\n        - 日志内容不光能支持字符串哟，大家如果传递数组、对象等作为参数，一样可以打印到 Console 中。\n    - 第二个参数是 **日志类型**：\n        - 可选，如果没有指定日志类型，则默认类型为 log。\n    - 第三个参数是 **自定样式**：\n        - 在这里写上你的自定义 css 样式即可。\n\n### 3、配置：\n在载入 slog.function.php 文件后，还可以对 SocketLog 进行一些配置。\n- 1， SocketLog 配置实例：\n\n    例如，将程序的报错信息也输出到 Console，示例代码如下：\n\n    ```php\n    \u003c?php\n    include './php/slog.function.php';\n\n    // 输出报错信息\n    slog(\n        array('error_handler' =\u003e true),  // error_handler 需要设置为 true\n        'config'\n    );\n    echo notice; // 制造一个 notice 报错\n\n    // 输出一般日志\n    slog('这里是输出的一般日志');\n    ```\n    - 配置解析：\n        - 第一个 slog() 函数有两个参数，第一个参数 **传递配置项的数组**，第二个参数 **设置为 config**。\n        - 第二个 slog() 函数，将字符串消息直接输出。\n\n- 2，支持的其他配置项：\n\n    ```php\n    \u003c?php\n    include './php/slog.function.php';\n\n    slog(\n        array(\n            'enable'              =\u003e true,        // 是否打印日志, [true | false]\n            'host'                =\u003e 'localhost', // WebSocket 服务器地址，默认为 localhost\n            'optimize'            =\u003e false,       // 是否显示有利于程序优化的信息，如运行时间、吞吐率、消耗内存等，默认为 false\n            'show_included_files' =\u003e false,       // 是否显示本次程序运行加载了哪些文件，默认为 false\n            'error_handler'       =\u003e false,       // 是否接管程序错误，将程序错误显示在 Console 中，默认为 false\n            'force_client_id'     =\u003e '',          // 日志强制输出到配置的 client_id，默认为空\n            'allow_client_ids'    =\u003e array()      // 限制允许读取日志的 client_id，默认为空，表示所有人都可以获得日志。\n        ),\n        'config'\n    );\n    ```\n    - 参数解析：\n        - **optimize**\n            - 若设置为 true，则日志中显示有利于程序优化的信息。\n            - 如：`[运行时间：0.081346035003662s][吞吐率：12.29req/s][内存消耗：346,910.45kb]`\n        - **show_included_files**\n            - 若设置为 true，则显示出程序运行时加载了哪些文件。\n            - 比如，我们在分析开源项目时，如果不知道模板文件在那里，往往需要看一下加载的文件列表。\n        - **error_handler**\n            - 若设置为 true，则接管报错，将错误信息打印到浏览器 Console。\n            - 在开发时 notice 信息能让我们快速发现 bug，但是有些 notice 是不可避免的，如果让他们显示在页面中会影响网页的正常布局，那么设置 error_handler 为 true，可让它显示在浏览器 Console 中，问题成功解决。\n    - 另外，此功能结合 [鸟哥](https://www.laruence.com/) 开发的 PHP Taint 也是极佳的。\n        - Taint 能自动检测出 XSS、SQL 注入、Shell注入等漏洞。\n        - 如果只用 PHP Taint，它的 warning 报错只告诉了变量输出的地方，并不知道变量在哪里赋值、怎么传递？\n        - 通过 SocketLog，能看到调用栈，可以轻松地对有问题的变量进行跟踪。更多 Taint 的信息请参考 [这里](https://www.laruence.com/2012/02/14/2544.html)。\n\n- 3，设置 client_id\n\n    在 Chrome 浏览器中，可以设置插件的 client_id，可以是你任意指定的字符串。\n\n    ![设置插件的 client_id](./screenshots/socketlog.png)\n\n    **设置了 client_id 后能实现以下功能：**\n    - 1，设置 allow_client_ids 配置项，只允许指定的浏览器获取日志，这样就可以把调试代码带上线。\n        - 普通用户访问不会触发调试，也不会收到调试日志，而开发人员访问就能看到调试日志，这样有利于找线上 bug。\n        - client_id 建议设置为：姓名拼音+随机字符串形式，原因有二。\n            - 其一，如果有员工离职可以将其对应的 client_id 从配置项 allow_client_ids 中移除。\n            - 其二，加上随机字符串，目的是防备别人根据你公司员工姓名猜测出 client_id，获取线上的调试日志。\n\n        - 设置 allow_client_ids 的示例代码：\n            ```php\n            slog(\n                array(\n                    'allow_client_ids' =\u003e array('luofei_zfH5NbLn', 'easy_DJq0z80H')    // 可设置多个 cliet_id\n                ),\n                'set_config'\n            );\n            ```\n\n    - 2，设置 force_client_id 配置项，让后台脚本也能输出日志到 Console 中。\n\n        - 网站有可能使用了队列，一些业务逻辑通过后台脚本处理，由于后台脚本不和浏览器接触，并不知道当前触发程序的是哪个浏览器。所以如果需要调试，我们就需要强制将日志打印到指定 client_id 的浏览器上。\n        - 因此在后台脚本中使用 SocketLog 时，设置 force_client_id 配置项，指定要强制输出浏览器的 client_id 即可（只可设置一个 client_i）。\n        - 设置 force_client_id 的示例代码：\n            ```php\n            \u003c?php\n            include './php/slog.function.php';\n\n            slog(\n                array(\n                    'force_client_id' =\u003e 'luofei_zfH5NbLn'    // 只可设置一个 cliet_id\n                ),\n                'config'\n            );\n            slog('test');\n            ```\n\n### 4，支持 composer（暂不推荐）：\n\n- 1，使用 composer 的安装命令如下：\n\n    \u003e 注意：通过 composer 方式安装的文件版本较旧，有些问题，不能直接使用，故不推荐。\n    ```shell\n    composer require luofei614/socketlog\n    ```\n- 2，直接调用静态方法\n    ```php\n    \u003c?php\n    require './vendor/autoload.php';\n\n    use think\\org\\Slog;\n\n    // 配置 SocketLog\n    Slog::config(\n        array(\n            'enable'              =\u003e true,        // 是否打印日志, [true | false]\n            'host'                =\u003e 'localhost', // WebSocket 服务器地址，默认为 localhost\n            'optimize'            =\u003e false,       // 是否显示有利于程序优化的信息，如运行时间、吞吐率、消耗内存等，默认为 false\n            'show_included_files' =\u003e false,       // 是否显示本次程序运行加载了哪些文件，默认为 false\n            'error_handler'       =\u003e false,       // 是否接管程序错误，将程序错误显示在 Console 中，默认为 false\n            'force_client_id'     =\u003e '',          // 日志强制输出到配置的 client_id，默认为空\n            'allow_client_ids'    =\u003e array()      // 限制允许读取日志的 client_id，默认为空，表示所有人都可以获得日志。\n        )\n    );\n\n    Slog::log('log');      // 一般日志\n    Slog::error('msg');    // 错误日志\n    Slog::info('msg');     // 信息日志\n    Slog::warn('msg');     // 警告日志\n    Slog::trace('msg');    // 输出日志，同时会打出调用栈\n    Slog::alert('msg');    // 将日志以 alert 方式弹出\n    Slog::log('msg', 'log', 'color:red;font-size:20px;');  // 自定义日志的样式，第三个参数为 css 样式\n    ```\n\n### 5，支持 ThinkPHP：\nThinkPHP5 之后，在框架层集成了 SocketLog，只需要设置配置即可用。参考：[远程调试](http://www.kancloud.cn/manual/thinkphp5/156120)\n\n### 6，对数据库进行调试：\nSocketLog 还能对 SQL 语句进行调试，自动对 SQL 语句进行 explain 分析，打印出有性能问题的 SQL 语句。 如下图所示。\n\n![对 SQL 语句进行 explain 分析](./screenshots/sql.png \"对 SQL 语句进行 explain 分析\")\n\n- 图片解析：\n    - 图中显示出了三条 SQL 语句，第一条 SQL 语句字体较大，是因为它有性能问题，在 SQL 语句的后台已经标注 Using filesort。\n    - 我们还可以点击某个 SQL 语句查看它执行的调用栈，清楚地知道 SQL 语句是如何被执行的，方便我们分析程序、方便做开源程序的二次开发。\n    - 图中第三条 SQL 语句为被点开的状态。\n\n- 实际用例：\n\n    - 用 slog() 函数打印 SQL 语句时，第二个参数传递 mysql 或 mysqli 的对象即可。\n\n- 示例代码：\n    ```php\n    $link = mysql_connect('localhost:3306', 'root', '123456', true);\n    mysql_select_db('kuaijianli', $link);\n\n    $sql = \"SELECT * FROM `user`\";\n\n    slog($sql, $link);\n    ```\n    后面会以 OneThink 为例再对数据库调试进行演示\n\n    借助上面的方法，SocketLog 还能自动为你检测出没有 where 条件的 SQL 操作，然后自动提示你。\n\n\u003e 注意：有时候在数据比较少的情况下，MySQL 查询不会使用索引，explain 也会提示 Using filesort 等性能问题，其实这时候并不是真正有性能问题，你需要自行判断，或者增加更多的数据再测试。\n\n### 7，对 API 进行调试：\n网站调用了 API ，如何将 API 程序的调试信息也打印到浏览器的 Console 中？\n\n- 方法一：配置 force_client_id\n    - 前面我们讲了一个 force_client_id 配置，能将日志强制记录到指定的浏览器。这种方法同样适用于将 API 的调试信息打印到 Console 中。\n    - 缺点： force_client_id 只能指定一个 client_id，如果我们的开发环境是多人共用，这种方式就不方便了。\n\n- 方法二：识别 User-Agent\n    - 其实只要将浏览器发送的 User-Agent 再传递给 API，API 程序中不用配置 force_client_id，也能识别当前访问程序的浏览器，将日志回传回来。\n    - 我们需要将 SDK 代码稍微做一下修改。调用 API 的 SDK，一般是用 curl 写的，添加下面的代码可以将浏览器的 User-Agent 传递到 API 。\n        ```php\n        $headers = array();\n        if (isset($_SERVER['HTTP_USER_AGENT'])) {\n            $headers[] = 'User-Agent: ' . $_SERVER['HTTP_USER_AGENT'];\n        }\n\n        if (isset($_SERVER['HTTP_SOCKETLOG'])) {\n            $headers[] = 'Socketlog: ' . $_SERVER['HTTP_SOCKETLOG'];\n        }\n\n        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);\n        ```\n\n### 8，区分正式和开发环境：\n- 1，进入 Chrome 浏览器的 “更多工具” ----\u003e “扩展程序(E)” 或者直接在地址栏输入 `chrome://extensions/`，打开扩展程序列表页。\n\n- 2，找到 “SocketLog” 然后点击 “详细信息”，打开 SocketLog 的详细页。\n\n![SocketLog 详细信息](./screenshots/SocketLog-detail-msg.png \"SocketLog 详细信息\")\n\n- 3，找到“扩展程序选项”，点击右侧的按钮。\n\n![扩展程序选项](./screenshots/SocketLog-extension-options.png \"扩展程序选项\")\n\n- 4，此时在打开的 SocketLog Options 页，可以设置 “特殊环境域名” 和 “正式环境域名”。\n\n![设置开发环境的域名](./screenshots/SocketLog-Options-env.png \"设置开发环境的域名\")\n\n### 9，分析开源程序：\n\n有了 SocketLog，我们能很方便的分析开源程序，下面以 OneThink 为例，大家可以在 http://www.topthink.com/topic/2228.html 下载最新的 OneThink 程序。 安装好 OneThink 后，按下面步骤增加 SocketLog 程序。\n\n- 1，将 slog.php 复制到 OneThink 的程序目录中，如果没有想好将文件放到哪个子文件夹，可以暂且放到根目录。\n- 2，编辑入口文件 index.php，在代码的最前面加载 slog.function.php，并设置 SocketLog。\n    ```php\n    \u003c?php\n    include './slog.function.php';\n    slog(\n        array(\n            'error_handler'       =\u003e true,\n            'optimize'            =\u003e true,\n            'show_included_files' =\u003e true\n        ),\n        'config'\n    );\n    ```\n\n- 3，编辑 ThinkPHP/Library/Think/Db/Driver.class.php 文件，在这个类中的 execute() 方法为一个执行 SQL 语句的方法，增加代码：\n    ```php\n    slog($this-\u003equeryStr, $this-\u003e_linkID);\n    ```\n- 4，类中的 query() 方法也是一个执行 SQL 语句的地方，同样需要增加上面的代码。\n\n- 5，然后浏览网站看看效果：\n\n![enter image description here](./screenshots/onethink.png)\n\n通过 Console 的日志，访问每一页我们都知道程序干了些什么，这是一件很爽的事情。\n\n\u003e 提示：\n另一种更简单的方法，因为 OneThink 每次执行完 SQL 语句都会调用 `$this-\u003edebug`， 所以我们可以把 `slog($this-\u003equeryStr, $this-\u003e_linkID);` 直接写在 `Db.class.php` 文件的 debug() 方法中。 这样不管是 mysqli 还是 mysql 驱动都有效。\n\n## 三，视频教程\n[http://edu.normalcoder.com/course/941](http://edu.normalcoder.com/course/941)\n\n感谢猿团的张盛翔（诺墨）提供教程。\n\n## 四，About Me\n* Author: @luofei614 新浪微博：http://weibo.com/luofei614\n* 优伯立信创始人，ThinkPHP核心开发者之一，待过新浪云计算\n\n[1]: https://github.com/luofei614/SocketLog/raw/master/screenshots/discuz.png\n[2]: https://github.com/luofei614/SocketLog/raw/master/screenshots/socketlog.png\n[3]: https://github.com/luofei614/SocketLog/raw/master/screenshots/sql.png\n[4]: https://github.com/luofei614/SocketLog/raw/master/screenshots/onethink.png\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fluofei614%2FSocketLog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fluofei614%2FSocketLog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fluofei614%2FSocketLog/lists"}