Backstage 部署监控指南:使用 OpenTelemetry 与 Analytics API 打造可观测的开发门户

发布时间:2026/9/10 19:54:14

Backstage 部署监控指南:使用 OpenTelemetry 与 Analytics API 打造可观测的开发门户 Backstage 部署监控指南使用 OpenTelemetry 与 Analytics API 打造可观测的开发门户【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage本文是一份面向 Backstage 运维管理员的部署监控实战指南。生产环境中的 Backstage 需要可观测性来跟踪系统健康、诊断问题和理解使用模式为此 Backstage 在后端提供了内建的 OpenTelemetry 支持指标与追踪在前端提供了事件驱动的 Analytics API。读完本文你将掌握如何为后端接入 OpenTelemetry 导出器Prometheus 指标、OTLP 追踪、如何利用内置健康检查端点配置 Kubernetes 探针、如何为前端接入第三方分析工具并理解其事件模型以及如何利用结构化 JSON 日志接入日志聚合系统。监控总览两条可观测性主线Backstage 的可观测性设计围绕两条主线展开后端通过 OpenTelemetry 上报指标metrics与追踪traces结合内置的健康检查端点health check endpoints与结构化 JSON 日志覆盖系统的健康、性能与运行状态。前端通过事件驱动的 Analytics API 追踪用户行为帮助理解哪些插件使用最频繁量化 Backstage 投资的回报ROI同时可配合 Sentry、CloudWatch RUM、Cloudflare RUM 等服务做客户端错误上报。两条主线互补后端指标回答系统是否健康、是否高效前端分析回答用户如何使用系统。下面分别展开。后端监控OpenTelemetry 接入Backstage 使用 OpenTelemetry 上报指标与追踪。接入流程分为三步安装 OpenTelemetry 依赖包、创建插桩instrumentation文件、在后端启动前加载该文件。完整的分步教程见 Setup OpenTelemetry 教程下文直接给出可操作的完整流程。安装依赖在packages/backend中安装 OpenTelemetry Node SDK 与自动插桩包yarn --cwd packages/backend add \ opentelemetry/sdk-node \ opentelemetry/auto-instrumentations-node \ opentelemetry/exporter-prometheus \ opentelemetry/exporter-trace-otlp-http各包职责如下opentelemetry/sdk-nodeOpenTelemetry Node.js SDK负责装配指标读取器metric reader与追踪导出器trace exporter。opentelemetry/auto-instrumentations-node自动插桩库为 Express 等被调用库中的代码自动创建 spans。opentelemetry/exporter-prometheusPrometheus 指标导出器默认在localhost:9464/metrics暴露指标。opentelemetry/exporter-trace-otlp-httpOTLP HTTP 追踪导出器将 traces 通过 HTTP 发送到如 Jaeger 等目标。从源码看Backstage 的插件如 catalog本身就在使用 OpenTelemetry API 发送自定义 traces 和 metrics例如 catalog-backend 的数据库指标实现 通过metrics.createObservableGauge(...)注册catalog_entities_count、catalog_registered_locations_count、catalog_relations_count等观测指标。auto-instrumentations-node则负责捕获框架层的自动插桩数据。教程中使用 Prometheus 导出器做演示你可以按需替换为其他导出器例如参考 OTLP exporters 相关文档追踪部分使用 JSON/HTTP 导出器、以 Jaeger 为理想目标同样可替换为你需要的工具。创建 instrumentation 文件在packages/backend/src目录下创建instrumentation.js// 防止因 worker 线程导致重复运行 const { isMainThread } require(node:worker_threads); if (isMainThread) { const { NodeSDK } require(opentelemetry/sdk-node); const { getNodeAutoInstrumentations, } require(opentelemetry/auto-instrumentations-node); const { PrometheusExporter } require(opentelemetry/exporter-prometheus); const { OTLPTraceExporter, } require(opentelemetry/exporter-trace-otlp-http); // 默认在 localhost:9464/metrics 导出指标 const prometheusExporter new PrometheusExporter(); // 将 traces 发送到 localhost:4318/v1/traces const otlpTraceExporter new OTLPTraceExporter({ // 默认 Jaeger URL 追踪端点 url: http://localhost:4318/v1/traces, }); const sdk new NodeSDK({ metricReader: prometheusExporter, traceExporter: otlpTraceExporter, instrumentations: [getNodeAutoInstrumentations()], }); sdk.start(); }几点说明使用isMainThread检查可以避免因 worker 线程Backstage 后台任务可能使用而多次初始化 SDK。getNodeAutoInstrumentations()返回全部自动插桩项实际部署时你很可能不需要全部建议按需精简只保留你真正用到的插桩。指标默认端口为9464路径为/metricsOTLP traces 默认端点为http://localhost:4318/v1/traces可按你的 Jaeger/Collector 部署位置调整。配置 Views 调整直方图桶OpenTelemetry 默认的直方图桶以毫秒为单位而 Catalog 处理流程产生的直方图指标以秒为单位。你可以通过 OpenTelemetry 的 Views 功能调整桶边界使其更贴合实际数据分布。统一调整所有直方图桶const prometheus new PrometheusExporter(); const sdk new NodeSDK({ metricReader: prometheus, views: [ new View({ instrumentName: catalog.test, aggregation: new ExplicitBucketHistogramAggregation([ 0.01, 0.1, 0.5, 1, 5, 10, 25, 50, 100, 500, 1000, ]), }), ], });更精细的定向配置const prometheus new PrometheusExporter(); const sdk new NodeSDK({ metricReader: prometheus, views: [ new View({ instrumentName: catalog.test, aggregation: new ExplicitBucketHistogramAggregation([ 0, 0.01, 0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 30, 60, 120, 300, 1000, ]), }), ], });上述代码中的instrumentName: catalog.test为演示名称实际使用时应替换为你关心的具体指标名如catalog.processing.duration。桶边界的选择应覆盖你预期的处理时长分布太小会导致高值全部落入最后一个桶失去区分度。本地开发配置关键在于 NodeSDK 与自动插桩必须在导入任何库之前完成初始化因此需要使用 Node.js 的--require标志详见 Node.js CLI 文档在应用启动前预加载插桩文件。在packages/backend/package.json的scripts中加入--require标志scripts: { start: backstage-cli package start --require ./src/instrumentation.js, ...随后正常执行yarn start启动 Backstage即可在http://localhost:9464/metrics看到指标输出。常见问题排查如果指标或追踪无法工作OpenTelemetry 提供了诊断工具。先安装opentelemetry/apiyarn --cwd packages/backend add opentelemetry/api然后在sdk.start()调用之前加入如下片段开启调试日志const { diag, DiagConsoleLogger, DiagLogLevel } require(opentelemetry/api); diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG);这会输出 OpenTelemetry 的调试日志帮助你定位问题。不建议在生产环境启用——DEBUG 级别的日志量非常大。此外OpenTelemetry 提供了大量 SDK 环境变量可用于禁用或配置特定功能如采样率、导出间隔等部署时可按需调整。生产环境配置Docker生产环境使用 Docker 部署时需要确保 instrumentation 文件被正确打入镜像并预先加载。第一步在.dockerignore中加入下面一行在推荐的标准.dockerignore配置下确保 Docker 构建不会忽略插桩文件!packages/backend/src/instrumentation.js第二步在Dockerfile中把instrumentation.js复制到工作目录根COPY --chown${NOT_ROOT_USER}:${NOT_ROOT_USER} packages/backend/src/instrumentation.js ./第三步在 CMD 数组中加入指向该文件的--require标志# 修改前 CMD [node, packages/backend, --config, app-config.yaml] # 修改后 CMD [node, --require, ./instrumentation.js, packages/backend, --config, app-config.yaml]可用指标清单以下是 Backstage 当前暴露的可用指标实际可用指标取决于你安装的插件及其版本下表来自本仓库的教程文档与插件源码指标名含义catalog_entities_countCatalog 中的实体总数带kind标签catalog_registered_locations_countCatalog 中已注册 location 的总数catalog_relations_count实体间关系relations的总数catalog.processed.entities.count已处理的实体数量catalog.processing.duration执行完整处理流程所花时间catalog.processors.duration执行 catalog processors 所花时间catalog.processing.queue.delay从被调度处理到实际开始处理之间的延迟catalog.stitched.entities.count已缝合stitched的实体数量catalog.stitching.duration执行完整缝合流程所花时间catalog.stitching.queue.length当前缝合队列中的实体数catalog.stitching.queue.delay从被调度缝合到实际开始缝合之间的延迟scaffolder.task.count任务运行次数计数器scaffolder.task.duration一次任务运行的耗时直方图scaffolder.step.count步骤运行次数计数器scaffolder.step.duration单次步骤运行耗时直方图backend_tasks.task.runs.count后台任务累计运行次数backend_tasks.task.runs.duration后台任务运行耗时的直方图backend_tasks.task.runs.started每个任务taskId标签最近一次启动的 Unix 时间戳秒Gaugebackend_tasks.task.runs.completed每个任务最近一次完成的 Unix 时间戳秒Gauge这些指标是设置告警的重要依据例如可以用catalog.processing.queue.delay监控处理积压用scaffolder.task.duration监控异常的慢任务。指标背后的源码实现Catalog 指标定义在 catalog-backend 数据库指标模块catalog_entities_count、catalog_registered_locations_count、catalog_relations_count同时以Prometheus Gauge已标记 DEPRECATED建议改用 OpenTelemetry 指标和OpenTelemetry ObservableGauge两种形式注册。其中实体计数从final_entities表读取而非体积大 2030 倍的search表并带有 30 秒 TTL 的单飞缓存来合并并发抓取查询避免每次 scrape 对数据库发起重复的重型查询。实体计数还按kind维度打标签查询时用数据库方言从entity_ref解析 kindPostgreSQL 用split_part、MySQL 用substring_index、SQLite 用substr/instr见 entityRefKindExpression。Scaffolder 指标定义在 NunjucksWorkflowRunner 的 scaffoldingTracker同样以 prom-client已标记 DEPRECATED和 OpenTelemetry 两种方式注册scaffolder.task.count、scaffolder.task.duration、scaffolder.step.count、scaffolder.step.duration其中 OpenTelemetry 版本带template/step/result标签unit: s明确以秒为单位与教程中Catalog 处理直方图以秒为单位的提示一致。prom-client 版本指标名使用下划线命名如scaffolder_task_countOpenTelemetry 版本使用点号命名如scaffolder.task.count二者是同一语义的双份实现。各插件通用的指标创建工具函数位于 catalog-backend util/metrics.ts 与 scaffolder-backend util/metrics.ts均为先查全局 register 是否已注册同名指标已注册则复用、否则新建的模式保证指标幂等创建。健康检查端点Backstage 内置了健康检查端点可用于 Kubernetes 或其他编排系统中的存活liveness与就绪readiness探针/.backstage/health/v1/readiness当后端已准备好对外提供流量时返回 healthy。/.backstage/health/v1/liveness当后端进程存活时返回 healthy。这两个端点在 createHealthRouter 中实现readiness端点调用RootHealthService.getReadiness()liveness端点调用getLiveness()二者都以对应 HTTP 状态码 JSON payload 响应。源码还支持通过backend.health.headers配置为健康检查响应附加自定义头例如供负载均衡器识别的标识这在 K8s 探针与外部 LB 健康检查结合的场景下非常有用。一个典型的 Kubernetes 探针配置示例livenessProbe: httpGet: path: /.backstage/health/v1/liveness port: backend readinessProbe: httpGet: path: /.backstage/health/v1/readiness port: backend前端分析Analytics APIBackstage 提供事件驱动的 Analytics API用于追踪前端用户行为。它既给应用集成方提供了在自选分析工具中收集和分析使用数据的灵活性也给插件开发者提供了为关键用户交互插桩的标准接口。完整说明见 Plugin Analytics 文档。核心概念Events事件至少由action如click和subject如被点击的东西组成。Attributes属性事件级别的附加维度数据键值对。例如用户点击跳转到的 URL 可表示为{ to: /a/page }。Context上下文事件发生的更广背景默认包含pluginId和extensionId。这种事件组合方式支持从多个粒度分析既能回答某个路由上被点击最多的是什么这样的细粒度问题也能回答我的 Backstage 实例中哪个插件使用最多这样的宏观问题。支持的 Analytics 工具Analytics 事件转发本质上是 AnalyticsApi 的一个具体实现常见的集成已打包为插件提供分析工具支持状态Google Analytics支持 ✅Google Analytics 4支持 ✅New Relic Browser社区 ✅Matomo社区 ✅Quantum Metric社区 ✅Generic HTTP社区 ✅本文档场景下你需要重点关注的三个是Google Analytics 4、New Relic Browser 与 Matomo前文 006-monitoring.md 明确列出的三个。关键事件以下表格总结了各插件可能捕获的关键事件取决于你安装了哪些插件ActionSubject其他说明navigate被导航到的页面 URL路由位置变化时立即触发若关联插件/路由数据不明确则推迟到数据可知后、下一个事件或文档卸载前触发。当前路由参数会作为 attributes 附带click被点击链接的文本to属性表示点击跳转的 URLcreate被创建软件的名称若模板未要求name属性则使用new {templateName}context 携带entityRef模板 ref如template:default/template-namevalue表示运行模板节省的分钟数基于模板的backstage.io/time-saved注解search任意搜索栏组件中输入的搜索词context 携带searchTypesvalue表示查询结果总数使用权限框架时可能不可见discover被点击的搜索结果标题value为结果排名同时提供to属性not-found导致 404 页面的资源路径至少由 TechDocs 触发编写自定义集成事件转发实现为 Backstage 的 Utility API只需提供单个captureEvent(event)方法。新版前端系统使用AnalyticsImplementationBlueprintimport { AnalyticsImplementationBlueprint } from backstage/plugin-app-react; export const acmeAnalyticsImplementation AnalyticsImplementationBlueprint.make({ name: acme, params: define define({ deps: {}, factory() { return { captureEvent: event { window._AcmeAnalyticsQ.push(event); }, }; }, }), });更完整的实现通常会封装初始化逻辑并从配置读取参数旧版前端系统使用createApiFactory(analyticsApiRef, ...)见 plugins/analytics.md 文档import { AnalyticsApi, AnalyticsEvent, configApiRef, } from backstage/frontend-plugin-api; import { AnalyticsImplementationBlueprint } from backstage/plugin-app-react; import { AcmeAnalytics } from acme-analytics; class AcmeAnalyticsImpl implements AnalyticsApi { private constructor(accountId: number) { AcmeAnalytics.init(accountId); } static fromConfig(config) { const accountId config.getString(app.analytics.acme.id); return new AcmeAnalyticsImpl(accountId); } captureEvent(event: AnalyticsEvent) { const { action, ...rest } event; AcmeAnalytics.send(action, rest); } } export const acmeAnalyticsImplementation AnalyticsImplementationBlueprint.make({ name: acme, params: define define({ deps: { configApi: configApiRef }, factory: ({ configApi }) AcmeAnalyticsImpl.fromConfig(configApi), }), });按社区惯例此类集成包应命名为backstage/analytics-module-[name]配置统一放在app.analytics.[name]键下。如果分析平台有一等公民的用户身份概念可约定以identityApi作为依赖并用identityApi.getBackstageIdentity()解析出的userEntityRef作为发送给平台的基础用户 ID。捕获自定义事件在组件中通过useAnalytics()钩子获取 tracker来自backstage/frontend-plugin-api其captureEvent方法接收action与subject参数import { useAnalytics } from backstage/frontend-plugin-api; const analytics useAnalytics(); analytics.captureEvent(deploy, serviceName);捕获的事件应反映用户意图和插件专属的领域动作而不是通用点击或 UI 生命周期事件。许多backstage/ui组件如Link、ButtonLink、Tab、MenuItem、Tag、Table行会自动捕获click事件因此通常不需要手动插桩导航类点击如果默认事件不满足需求可传入noTrackprop 关闭默认捕获并在自己的点击处理器中调用captureEvent。附加属性与数值第三个options参数可携带维度attributes和数值valueanalytics.captureEvent(merge, pullRequestName, { value: pullRequestAgeInMinutes, attributes: { org, repo, }, });对应捕获到的事件对象{ action: merge, subject: Name of Pull Request, value: 60, attributes: { org: some-org, repo: some-repo } }上下文提供对于只在 React 树上层的元数据使用AnalyticsContext包裹context 可嵌套沿 React 树向下合并允许键被覆盖核心自动附带的pluginId、extensionId始终存在import { AnalyticsContext, useAnalytics } from backstage/frontend-plugin-api; const MyComponent ({ value }) { const analytics useAnalytics(); const handleClick () analytics.captureEvent(check, value); return SomeThing value{value} onClick{handleClick} /; }; const MyWrapper () { return ( AnalyticsContext attributes{{ segment: xyz }} MyComponent value{Some Value} / /AnalyticsContext ); };事件命名建议避免使用过于具体的action例如用filter而非filterEntityTable让extensionId自动携带EntityTable上下文添加 attributes/context 时参考既有事件保持键的意图、类型甚至内容一致例如 Catalog 相关事件通常包含entityRef上下文键以便跨插件聚合分析。单元测试backstage/frontend-test-utils提供MockAnalyticsApi可在测试中配合TestApiProvider注入analyticsApiRef用apiSpy.getEvents()断言捕获的事件内容action、subject、attributes 等。前端错误上报除了行为分析还应考虑接入客户端错误上报服务如 Sentry、CloudWatch RUM、Cloudflare RUM用于捕获和诊断前端运行时错误。这是对 Analytics 的有力补充分析回答用户在做什么错误上报回答用户遇到了什么问题。日志结构化 JSON 输出Backstage 后端默认向 stdout 输出结构化 JSON 日志包含service、plugin、level、message等字段可直接被 Elasticsearch、Datadog、Splunk 等日志聚合工具解析。这意味着你无需编写额外的日志解析逻辑只需将 stdout 采集到日志管道即可。实际使用建议在 Kubernetes 中容器 stdout 会被 kubelet 自动收集到节点日志目录配合 DaemonSet 日志采集器如 Filebeat、Fluentd即可汇入聚合平台。可基于level字段如error、warn配置日志告警与指标告警互为补充。plugin字段可用于按插件维度分析错误分布快速定位问题插件。下一步规模化监控随着更多用户采用你的 Backstage 实例监控数据会帮助你判断何时需要扩容——例如 API 响应时间上升、catalog.processing.duration显示 Catalog 处理落后、scaffolder 任务排队时间超出预期、用户反馈页面加载缓慢等信号。扩容前优先考虑水平扩展增加副本这比拆分后端更简单且能覆盖大多数增长场景。详见 Scaling your deployment 与 Scaling Backstage Deployments。参考资源本指南出处Golden Path 部署系列 · Monitoring your deploymentOpenTelemetry 完整接入教程Setup OpenTelemetry前端分析完整文档Plugin Analytics新前端系统 与 Plugin Analytics旧文档健康检查端点实现createHealthRouter.tsCatalog 指标实现database/metrics.tsScaffolder 指标实现NunjucksWorkflowRunner.ts【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/10 19:54:14

P2G两阶段建模:电解水制氢与甲烷化的Matlab实现与仿真

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/10 19:54:14

Manus恢复独立运营,通用Agent行业重构与用户应对策略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/10 20:44:19

CANN/GE模型描述获取API

aclmdlGetDescFromFile 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、Ten…

2026/9/10 20:44:19

cann/ge 获取数据集缓冲区API

aclmdlGetDatasetBuffer 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、Te…

2026/9/10 20:39:18

Python实现轻量级日志监控与警报系统

1. 项目概述:日志监控与警报系统的核心价值日志监控是系统运维中最基础也最重要的环节之一。记得去年我们团队就遇到过一次线上事故——某核心服务突然崩溃,但由于缺乏实时日志监控,直到用户投诉才发现问题,整整耽误了40分钟。这件…

2026/9/10 16:39:38

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/10 11:16:38

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/9 16:31:09

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/10 0:00:55

目录对比去重实战:用哈希算法精准清理重复文件

我电脑里现在还有一块换了三次机的“数据墓地”硬盘,里面存着2016年以前所有旧笔记本的完整备份。平时不觉得有什么,直到前阵子想把它整理归档,发现同一个安装包、同一批照片、同一份论文草稿,在几个不同的备份目录里反复出现。更…

2026/9/10 0:00:55

Leaflet离线地图完整Demo合集:内网部署与坐标纠偏实战

简介:这是一份面向Web GIS开发者的LeafLet离线地图示例合集,帮助开发者快速掌握离线地图从搭建到交互的完整流程。压缩包共723个文件,大小14.06MB,以319个js脚本、175个html页面和29个css样式文件为主体,配合png/svg图…

2026/9/10 0:00:55

MATLAB读取Rinex 3.02观测文件:多系统GNSS数据解析实战

简介:基于MATLAB开发的Rinex3.02版观测文件(o文件)读取代码包,面向卫星定位导航方向的学习者与研究人员,用于解决新版观测文件的数据解析、历元提取与时间转换问题。压缩包共4个文件,包含两个m脚本、一个19…

2026/9/10 12:32:02

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/10 15:19:50

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/10 15:49:53

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码