只有累積,沒有奇蹟

2024年11月4日 星期一

[Windows] 註冊 Windows Service 服務

前言
最近專案有個需求要將排程透過 Windows Service 服務來執行,在 Windows OS 要註冊 Service 可以用  cmd  與  powershell  兩種方式來建立以及刪除 Service,兩種方式之前都有使用過但要再使用時都會上網查因此決定紀錄一下未來方便查詢,此篇就針對這兩種方式進行基本介紹與說明若有問題歡迎提出一起討論或是給予指導。

使用命令提示字元 cmd
在執行時請先注意開啟 cmd 需要使用 Admin 權限執行,否則會有執行異常或是告知沒權限的錯誤訊息,以下為開啟時應用程式時用 administrator 開啟的畫面,用管理者身分執行 cmd

註冊服務
在 cmd 中可以透過 sc.exe 來建立 windows service,sc 全名為 service control,語法指令格式如下說明
描述:
        在登錄和服務資料庫中建立服務項目。
使用方法:
        sc <server> create [service name] [binPath= ] <option1> <option2>...

選項:
注意: 選項名稱包括等號。
      在等號和值之間必須空一格。
 type= <own|share|interact|kernel|filesys|rec|userown|usershare>
       (預設值 = own)
 start= <boot|system|auto|demand|disabled|delayed-auto>
       (預設值 = demand)
 error= <normal|severe|critical|ignore>
       (預設值 = normal)
 binPath= <.exe 檔案的二進位檔案路徑名稱>
 group= <載入順序群組>
 tag= <yes|no>
 depend= <相依性(以 / (反斜線) 隔開)>
 obj= <帳戶名稱|物件名稱>
       (預設值 = LocalSystem)
 DisplayName= <顯示名稱>
 password= <密碼>
舉例來說,要註冊 Windows Service 名為 TestService,其檔案位置在 D:\Job\TestService\Test.Jobs.exe 位置中,可以透過  create ServiceName  指令建立
D:\>sc create TestService binPath="D:\Job\TestService\Test.Jobs.exe"
[SC] CreateService 成功
建立成功可以看到新增 TestService 成功的訊息,接著我們使用   query ServiceName  查詢目前 service 狀態,剛建立好的 service 狀態會是 STOPPED (1)
D:\>sc query testservice

SERVICE_NAME: testservice
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 1  STOPPED
        WIN32_EXIT_CODE    : 1077  (0x435)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0

啟動服務
可以透過  start ServiceName  指令來啟動服務,要啟動時狀態為 START_PENDING (2)
D:\>sc start testservice

SERVICE_NAME: testservice
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 2  START_PENDING
                                (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x7d0
        PID                : 26300
        FLAGS              : 
當正常執行,狀態就會更新為 RUN (4) 
SERVICE_NAME: testservice
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 4  RUNNING
                                (STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0

停止服務
要停止服務的可以透過  stop ServiceName 指令,執行完指令會進行停止的動作,因此查看當下狀態會是 STOP_PENDING,當停止後再次查詢可以看到狀態改為 STOPPED (1)
D:\>sc stop testservice

SERVICE_NAME: testservice
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 3  STOP_PENDING
                                (STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0

D:\>sc query testservice

SERVICE_NAME: testservice
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 1  STOPPED
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0

刪除服務
當要刪除服務的話執行  delete ServiceName  指令,其回傳訊息與 create 類似直接回傳刪除服務成功
D:\>sc delete testservice
[SC] DeleteService 成功

使用 Powershell 
同樣的在執行前需要使用管理者身分執行 powershell,否則會有執行異常或是告知沒權限的錯誤訊息,
以下為開啟時應用程式時用 administrator 開啟的畫面

註冊服務
在 cmd 中可以透過 sc.exe 來建立 windows service,sc 全名為 service control,語法指令格式如下說明
PS C:\> New-Service -Name "TestService" -BinaryPathName "D:\Jobs\TestService\Jobs.exe" -DisplayName "Test Service" -StartupType Manual -Description "This is a test service."

Status   Name               DisplayName
------   ----               -----------
Stopped  TestService        Test Service
參數介紹


  • Name : 指定服務的名稱 (唯一)
  • BinaryPathName : 服務的執行檔案路徑位置
  • DisplayName : 顯示的名稱
  • StartupType : 啟動類型
  • Description : 描述
  • 建立成功之後,在 GUI 呈現畫面如下
    要註冊 Windows Service 名為 TestService,其檔案位置在 D:\Job\TestService\Test.Jobs.exe 位置中,可以透過  create ServiceName  指令建立
    D:\>sc create TestService binPath="D:\Job\TestService\Test.Jobs.exe"
    [SC] CreateService 成功
    建立成功,接著我們查詢目前 service 狀態,在 powershell 指令比 cmd 稍微多一滴滴要使用 win32service在透過 filter 來查詢剛建立好的 testservice,與 cmd 建立的相同剛建好的狀態都是 Stopped 
    PS C:\> Get-WmiObject win32_service -Filter "name='testservice'"
    
    ExitCode  : 1077
    Name      : TestService
    ProcessId : 0
    StartMode : Manual
    State     : Stopped
    Status    : OK

    啟動服務
    可以透過  start ServiceName -Name  指令來啟動服務,與 cmd 不同的是會等到 running 在顯示目前狀態
    PS C:\> Start-Service -Name "testservice"
    PS C:\> Get-WmiObject win32_service -Filter "name='testservice'"
    
    ExitCode  : 0
    Name      : TestService
    ProcessId : 18188
    StartMode : Manual
    State     : Running
    Status    : OK              : 

    停止服務
    使用  stop ServiceName  指令停止當下 windows service,執行完指令會進行停止的動作,再次查詢服務狀態就會是已停止 STOPPED
    PS C:\> Stop-Service -Name "testservice"
    PS C:\> Get-WmiObject win32_service -Filter "name='testservice'"
    
    ExitCode  : 0
    Name      : TestService
    ProcessId : 0
    StartMode : Manual
    State     : Stopped
    Status    : OK

    刪除服務
    在 powersehll 中刪除時要特別注意,官方 MSDN 中提供的 Remove service 是 powershell 6 才提供的新功能,如果您的 powershell 版本低於 6 時候執行 remove serv 則會跳出錯誤訊息 : 無法辨識 'Remove-Service' 詞彙是否為 Cmdlet、函數,如果不確定電腦中使用的 powershell 版本為何,可以輸入以下指令
    PS C:\> $PSVersionTable.PSVersion
    
    Major  Minor  Build  Revision
    -----  -----  -----  --------
    5      1      17763  316
    因此,Remove service 會根據版本不同執行不同的指令,如果 powershell 是 6.0 或以上請輸入指令
    Remove-Service someservice 
    powershell 是 6.0 以下
    Stop-Service 'testservice'; Get-CimInstance -ClassName Win32_Service -Filter "Name='testservice'" | Remove-CimInstance
    

    後記
    透過以上簡單的介紹說明了在 cmd 與 powershell 中如何新增、刪除、查詢及修改 windows service 的各種方式與指令,如果有需要更細節的內容說是說明,可以透過 MSDN 官方網站查詢相關指令與更多的應用細節,這裡就針對簡單操作做說明不在琢磨,希望自己的金魚腦寫完這篇之後可以記錄得更清楚些 ! 

    參考
    powershell create windows service

    2024年10月26日 星期六

    [NET] 使用 MethodBase.GetCurrentMethod 取得執行方法資訊

    前言 
    在過去 method 發生例外用 catch 包起來時,往往 catch 寫的 logName 都是 hard Code 寫死 method Name,但常常會發生 copy 來 copy 去的時候忘記改寫死的 method name 造成 log 寫錯誤狀況發生,之前使用 C# 4.5 提供的 CallerMemberName attribute 解決此問題簡單範例如下
    private void Test(string message, [CallerMemberName] string memberName = "")
    {
        try
        {
            // do something
        }
        catch (Exception e)
        {
            Console.WriteLine($"Error Method : {memberName} , Message : {message}");
        }
    }
    但在 Method 都必須加上參數 CallerMember,此篇文章介紹另一種方式解決此問題

    使用方式
    在命名空間 System.Reflection 可以用 MethodBase 靜態方法取得當前方法的相關資訊,使用方式如下所示
    MethodBase.GetCurrentMethod()
    在 GetCurrencyMethod 方法還可以取得方法名稱、命名空間、全名等資訊
    MethodBase.GetCurrentMethod().Name ;
    MethodBase.GetCurrentMethod().DeclaringType.Namespace;
    MethodBase.GetCurrentMethod().DeclaringType.FullName;
    
    再回到今天想解決的問題,在發生例外使用用 Methodbase 取代 CallerMember 取得當下執行的方法,即可不用在 hardCode 在例外的訊息中,不用擔心 copy 到其他地方要再修改的問題,使用前須先using system.reflection 命名空間範例 Code 如下
    using System.Reflection;
    
    static void Main(string[] args)
    {
        // 目前執行方法的類別名稱
        Console.WriteLine($"GetCurrentMethod.Name : {MethodBase.GetCurrentMethod().Name}");
        // 目前執行方法的命名空間
        Console.WriteLine($"GetCurrentMethod.DeclaringType.Namespace : {MethodBase.GetCurrentMethod().DeclaringType.Namespace}");
        // 目前執行方法的全名
        Console.WriteLine($"GetCurrentMethod.DeclaringType.FullName : {MethodBase.GetCurrentMethod().DeclaringType.FullName}");
    
        try
        {
            CallForException();
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception Method Name : {0} ", GetException(MethodBase.GetCurrentMethod(), e));
        }
    
        Console.ReadKey();
    }
    
    private static string GetException(MethodBase methodBase, Exception e)
    {
        StackTrace trace = new StackTrace(e);
        StackFrame previousFrame = null;
    
        foreach (StackFrame frame in trace.GetFrames())
        {
            if (frame.GetMethod() == methodBase)
            {
                break;
            }
    
            previousFrame = frame;
        }
    
        return previousFrame?.GetMethod().Name;
    }
    
    private static void CallForException()
    {
        DoActualException();
    }
    
    private static void DoActualException()
    {
        throw new NotImplementedException();
    }
    輸出
    上面 sample Code 輸出如下
    • 執行的 method Name 為 main
    • 執行的 method Name 命名空間為 consoleApp1 
    • 發生例外 try catch 裡的方法名稱為 CallForException
    輕鬆上手,打完收工 !!

    參考
    MethodBase.GetCurrentMethod Method

    2024年9月14日 星期六

    [conference] DDDesign TW 2024 - Panel Discussion : 遺留工作負載(legacy workloads)

    分享心得
    從開發運維的角度來分享關於遺留工作負載(legacy workloads)的經驗與心得

    議程介紹
    主題 : 從開發運維的角度來分享關於遺留工作負載(legacy workloads)的經驗與心得
    今年主題爲「系統設計與社會技術年會(System Design & Socio-technical Conference)」。
    
    圍繞「遺留工作負載(legacy workloads)」和現代應用程式的演變,邀請大家共同探討這些工作負載在當今商業環境中所帶來的挑戰和機遇。討論遺留工作負載的演進,以及如何應對它們的變化,並探索系統設計的複雜性,重點考慮社會技術因素對軟體開發決策和執行的影響。期待深入探討企業決策者和一線執行團隊之間的合作方式,以實現系統設計和開發的目標。因此,我們將邀請國內外的領域驅動設計實踐家來分享經驗,希望觀衆不論程度都能從演講、互動環節、工作坊中獲得啟發並產生改變。
    

    主辦單位 :DDD TW
    議程表 : 連結



    2024年8月5日 星期一

    [conference] COSCUP 2024 - 探索 OpenTelemetry Auto-Instrumentation 在 .NET 的核心技術

    分享心得
    OpenTelemetry 是 Github 開源專案中除了 K8S 外第二名的專案,也是在討論可觀測性時收集遙測數據標準工具,但在工具背後到底怎麼實踐的呢 ? 這邊就透過自己的小研究來分享核心奧妙之處,希望可以幫助到有幸的開發夥伴們 :)

    議程介紹
    主題 : 探索 OpenTelemetry Auto-Instrumentation 在 .NET 的核心技術
    在這場分享中,我們將深入探索 OpenTelemetry 自動儀器化在 .NET 中的實踐與挑戰。通過程式碼解析,我們將探索 Auto-Instrumentation 的工作原理和關鍵技術實作,並探討如何在盡量不影響性能的前提下實現高效的遙測數據收集。我們將示範如何定制和擴展 OpenTelemetry 的功能,以滿足各種業務需求,並分享配置和調整 OpenTelemetry 的最佳實踐。參與者將學習如何應對實際應用中的挑戰,並掌握提升應用可觀測能力和性能的實用技巧。
    

    主辦單位 : COSCUP 議程表 : 連結
    共筆 : https://hackmd.io/iN-9JL86R4CDSFfOrjbMNw
    投影片 : 連結



    2024年7月11日 星期四

    [conference] DevopsDays 2024 - From Observability to Observability Driven Development

    分享心得
    很高興可以再次於 DevOpsDays 分享可觀測性 Observability 相關議題,第一次分享時是在2022年分享可觀測性(Observability)的實踐,當時台灣在討論可觀測性還沒有太多人,但在國外及各大工具廠商大力宣傳下,Observability 變得相對重要,但重要之外對於開發者的日常作業或是開發流程會有甚麼樣的影響呢 ? 因此就思考與分享了 From Observability to Observability Driven Development 這主題,希望大家可以思考除了從 SRE 的角度之外,從開發者的角度可以幫助什麼 ? 以及在軟體開發前期可以多思考哪些事情,這樣系統上線後才可以提產品及維運帶來更大的幫助,以上是想要分享議程的主軸,歡迎大家提出來進行討論,Happy learning 🙂

    議程介紹
    主題 : From Observability to Observability Driven Development
    近幾年來,隨著軟體架構進化為微服務和雲原生技術的轉變,系統的複雜性急劇增加。 這種變化使得傳統的監控工具難以全面理解並快速適應變化。 在國外研討會越來越多人探討如何透過可觀測性來提高 DevOps 的效率。面對這樣的挑戰,可觀測性變得越來越重要,它不僅讓開發和維運團隊能夠監控系統,更能透過收集系統的遙測數據來深入理解系統的行為和性能。
    
    本次分享的內容將包括:
    
    可觀測性的介紹:定義可觀測性的基本概念及其在現代軟體開發中的關鍵角色。探討為何可觀測性對於成功實施 DevOps 至關重要,以及它如何協助開發人員高效的運維和快速的問題解決。
    可觀測性的演進 : 分析可觀測性在過去幾年是如何不斷演進與重新定義的歷程;並探討可觀測性的重要信號(Signals),如日誌(Log)、指標(Metrics)、追踪(Trace)的演化如何協助團隊更好地理解和管理系統,以及這些關鍵信號在提供系統洞察問題的侷限性,並探索如何克服這些挑戰以實現更全面的可觀測性。
    可觀測性驅動開發(O.D.D):如何將可觀測性轉變為一種推動開發的策略。將可觀測性原則整合到軟體開發生命週期的各階段中,從基礎的可觀測性措施到開發過程中的全面整合,開發團隊可以更早地發現和解決潛在的問題。
    

    主辦單位 : DevOpsDays Taipei
    議程表 : 連結
    共筆 : https://hackmd.io/@DevOpsDay/2024/%2F%40DevOpsDay%2FSy6azMu80
    投影片 : 連結



    2024年3月24日 星期日

    [NET] .NET Aspire From 0 To 1 : 可觀測性儀錶板

    前言
    上一篇與大家介紹關於 .NET Asipre 方案基本組成與概念,今天要介紹自己覺得 .NET Aspire 框架中重要的儀表板功能,此系列文目前會分為三篇分別是
    • .NET Aspire 快速入門 : 介紹 .NET Aspirea 的基礎知識,包括其設計理念、主要功能
    • .NET Aspire 可觀測性儀錶板 : 解釋 .NET Aspire 如何提供應用程式的可觀測性,包括如何蒐集遙測數據、監控和日誌記錄
    • .NET Aspire 整合 : 說明 .NET Aspire 如何與其他微軟雲服務(如 Azure)整合
    希望可以這系列文的介紹與分享,讓有興趣的開發夥伴們可以更進一步了解對 .NET Aspire 框架的認識,與若對於上述內容有問題或是不清楚的地方,歡迎提出來一起討論。


    探索 .NET Aspire 儀錶板
    在 Visual Studio 執行後即可以看到 .NET Aspire Dashboard,Dashboard 是透過 Blazor 所撰寫的應用程式,開發者可以在 .NET Aspire 儀表板頁面顯示正在執行的應用程式,透過此儀表板可以看到應用程式的各項資訊,包括日誌 (Logs)、遙測數據、Metrics 和環境配置等,提供開發者對於應用程式的狀態更進一步的理解與掌握即時資訊。
    Resource
    如同前一篇介紹的在專案 Apphost 中所設定 Redis、apiService 跟 webFrontend 名字,三個各自型別 (Type) 也有顯示在畫面的欄位上,其中 Redis 是透過 docker 啟動,開啟 Docker Desktop Dashboard 可以看到對應到相同的資料與狀態,分別是 in use 跟 Running,還有應用程式啟動時間與位置資訊
    Logs
    點擊 Logs 欄位可以顯示應用程式的 log 資訊,以 webfrondend 為例會看到 Log 內容是應用程式相關的 console logs 資訊,還包含 log 的 level 與 message 與 log 紀錄的時間。另外 Watch logs 旁邊還可以進行專案的切換,可以更方便的看到不同 instance 的 console log 重要資訊
    Detail
    在 .NET Aspire 會自動解析應用程式相關的 endpoint 與環境變數等 config 設定資訊,在將其資訊呈現在 Dashboard 頁面,像是跟第三方串接時串接的 endpoint url、feature toogle 的開關 flag 設定,預設這些內容是隱藏看不到的,需要在點擊右方的 icon 才看到的。這邊 OTEL 開頭的到專案中 config 檔可以發現找不到這些相關的設定參數,OTEL 是與 opentelemetry 相關的設定資訊,這些資訊說明晚點會在後面介紹。

    執行應用程式
    前面介紹了 Resources 與 Console 之後,下面三個重要功能 Structure、Traces 與 Metrics 是可觀測性常提到的三大支柱,在 .NET Aspire 之所以可以輕鬆地蒐集這些資訊,主要是因為在 .NET 8 底層及組件實做 OpenTelemetry 的標準並提供相關的 API,並在應用程式啟動時設定蒐集相關遙測數據資料,才可以在 .NET Aspire dashboard 中讓開發者看到相關的資訊。因此在介紹 Structure、Traces 與 Metrics 前要先透過執行應用程式 API 與功能,才可以蒐集相關遙測數據在 Dashboard 上觀察到應用程式執行的狀況。
    透過 Resources 中 webfrontend 點擊 endpoint 可以看到上面畫面,這是一個簡單的畫面資訊是透過後端載入回傳當天天氣相關的資料。我們可以重新整理畫面試著多呼叫 API,測試中可以發現有設定 cache 功能將資料 cache 10 秒後失效。接著我們回到功能看各數據收集的狀況。

    Structured logs
    Structured logs 功能可以查看應用程式所記錄的 Log 資訊,像是 log 的來源 (Resources)、Log Level 等級、發生的時間與 log 內容等重要資訊,以下是該功能中自己覺得實用的功能
    • 專案切換 : 進行 resources 的切換,當應用程式變多時這個功能就很需要
    • 搜尋 : 針對 log message 內容進行搜尋的動作,方便快速過濾不必要的資訊
    • 篩選 : 提供 log level 的篩選
    • Trace : 切換畫面到 Trace,找到此 request 相關的請求 log
    • Log entry detail : log 詳細內容,將所有 log 相關的 attribute 資訊全部呈現在畫面上
    Traces
    Traces 可以看到該請求所相依的服務或是依賴 service,當服務越切越細時當異常發生我們要找到其中哪個服務異常就會是一個重要的議題,舉例來說我們今天系統中有個登入 login 服務,系統背後可能經過自己系統的服務、第三方 SSO 像是 github、微軟 AAD 等第三方系統整合,最後再將資訊整合到既有系統的 Auth 服務,在將整體登入的結果回到前端的 Client Device,即使各應用程式有紀錄 log 但彼此這些 log 是沒有關聯,在盤查問題實就會花費很多時間,Trace 就是透過 TraceID 來將各自的 log 資訊串聯再一起,讓開發者可以透過類似上列畫面更快的定位可能發生異常的服務。
    上圖是 sample 專案中 /weather 請求作為範例進行簡單介紹
    • 請求資訊 : 該請求資訊所發生的時間、花費多久 (Duration)、經過多少服務 (Resource) 及經過多少個 Span
    • /weather API 的請求路徑,可以看到在此請求路徑(Span)中的 endpoint 及 httpmethod 方法
    • 呈現這個請求中每個 Span 的細節,各自占比以及所花費的時間,並以 Dashboard 方式呈現讓大家更容易理解可能的瓶頸點
    • Detail : 分別記錄 Span、Application 與 Event 三個資訊的 log 資訊,Span 是紀錄請求類的相關資訊像是 spanID、http method、使用的 Url 及 port。Application 類則是該 service 相關資訊,像是服務名稱、instance ID (多個服務時方便識別)、收集遙測數據實使用的 sdk Name / language 及版本,如下圖所示。
    Metrics
    Metrics 可以做為監控應用程式即時的狀況,在 .NET Aspire 中會依據應用程式列出需要的 metrics 指標內容
    以上圖為例是查看 http.client.request.durtion 的資訊,詳細資訊可以參考 MSDN ASP.NET Core metrics 了解更多資訊。

    Dashboard 實作原理
    .NET Aspire 提供可視化的 dashboard,讓開發人員在開發雲端應用程式時變得更簡單,那麼在背後是如何做到的呢 ? 我們可以看到 AspireSampleApp.ApiService 與 AspireSampleApp.Web 兩個專案中的啟動呼叫 builder.AddServiceDefaults(); 方法,在程式一開始透過 ConfigureOpenTelemetry 來蒐集應用程式相關的遙測數據資料,其內容如下
    public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicationBuilder builder)
    {
        builder.Logging.AddOpenTelemetry(logging =>
        {
            logging.IncludeFormattedMessage = true;
            logging.IncludeScopes = true;
        });
    
        builder.Services.AddOpenTelemetry()
            .WithMetrics(metrics =>
            {
                metrics.AddAspNetCoreInstrumentation()
                       .AddHttpClientInstrumentation()
                       .AddProcessInstrumentation()
                       .AddRuntimeInstrumentation();
            })
            .WithTracing(tracing =>
            {
                if (builder.Environment.IsDevelopment())
                {
                    // We want to view all traces in development
                    tracing.SetSampler(new AlwaysOnSampler());
                }
    
                tracing.AddAspNetCoreInstrumentation()
                       .AddGrpcClientInstrumentation()
                       .AddHttpClientInstrumentation();
            });
    
        builder.AddOpenTelemetryExporters();
    
        return builder;
    }  
      

    OpenTelemetry 是什麼
    由於在 Dashboard 分為三塊分別是 Logging、Traces 與 Metrics 三者,因此在上述程式碼的說明我分為三部分來說明,首先先來看一下程式方法中提到的 OpenTelemetry。如果提到可觀測性 Observability 一定會討論到 OpenTelemetry 這套收集遙測數據的標準,OpenTelemetry 是什麼呢
    OpenTelemetry 提供單一的開放原始碼標準和技術組合,可從雲端原生應用程式和基礎架構中擷取及匯出指標、追蹤記錄和記錄檔。
    
    目的是為了解決雲端原生應用程式在分散式系統中收集應用程式的遙測據據資料問題,像是指標和追蹤在過去有不同種蒐集方式,透過 OpenTelemetry 統一的標準,可以簡化及更有效地蒐集需要的資料內容,彙整到相關的技術廠商或是 open Source 專案,各程式語言可以透過 OpenTelemetry 所定義的標準將其其程式語言的方法實做出來,提供給各自的開發者使用,如果想要了解更多關於 OpenTelemetry 介紹,可以參考我之前在 Will 保哥粉絲團直播分享的 初探 OpenTelemetry 工具組:蒐集遙測數據的新標準,這裡就不在多加介紹


    Logging
    程式碼中 3~7 行,設定 logging 相關資訊主要執行程式碼如下
    builder.Logging.AddOpenTelemetry(logging =>
    {
        logging.IncludeFormattedMessage = true;
        logging.IncludeScopes = true;
    });  
    
    在 logging 中主要透過程式碼中的 Logging.AddOpenTelemetry 往下查看是使用底層 AddOpenTelemetryInternal 方法,透過 Visual Studio IDE 查看定義 sourece code 來探討背後做了哪些事情
    private static ILoggingBuilder AddOpenTelemetryInternal(
    	ILoggingBuilder builder,
    	Action? configureBuilder,
    	Action? configureOptions)
    {
    	Guard.ThrowIfNull(builder);
    
    	builder.AddConfiguration();
    
    	var services = builder.Services;
    
    	// Note: This will bind logger options element (eg "Logging:OpenTelemetry") to OpenTelemetryLoggerOptions
    	RegisterLoggerProviderOptions(services);
    
    	services.AddOpenTelemetrySharedProviderBuilderServices();
    
    	if (configureOptions != null)
    	{
    		// Note: Order is important here so that user-supplied delegate
    		// fires AFTER the options are bound to Logging:OpenTelemetry
    		// configuration.
    		services.Configure(configureOptions);
    	}
    
    	var loggingBuilder = new LoggerProviderBuilderBase(services).ConfigureBuilder(
    		(sp, logging) =>
    		{
    			var options = sp.GetRequiredService>().CurrentValue;
    
    			if (options.ResourceBuilder != null)
    			{
    				logging.SetResourceBuilder(options.ResourceBuilder);
    
    				options.ResourceBuilder = null;
    			}
    
    			foreach (var processorFactory in options.ProcessorFactories)
    			{
    				logging.AddProcessor(processorFactory);
    			}
    
    			options.ProcessorFactories.Clear();
    		});
    
    	configureBuilder?.Invoke(loggingBuilder);
    
    	services.TryAddEnumerable(
    		ServiceDescriptor.Singleton(
    			sp => new OpenTelemetryLoggerProvider(
    				sp.GetRequiredService(),
    				sp.GetRequiredService>().CurrentValue,
    				disposeProvider: false)));
    
    	return builder;
    
    #if NET6_0_OR_GREATER
    	[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "OpenTelemetryLoggerOptions contains only primitive properties.")]
    	[UnconditionalSuppressMessage("AOT", "IL3050", Justification = "OpenTelemetryLoggerOptions contains only primitive properties.")]
    #endif
    	static void RegisterLoggerProviderOptions(IServiceCollection services)
    	{
    		LoggerProviderOptions.RegisterProviderOptions(services);
    	}
    }    
    
    上述程式碼重點是在 .NET 程式中與 OpenTelemetry 進行配置日誌紀錄,通過 services.AddOpenTelemetrySharedProviderBuilderServices() 向 DI 加上 OpenTelemetry 相關服務,並在 RegisterLoggerProviderOptions(services) 綁定 OpenTelemetryLoggerOptions,使用 Singleton 方式新增到 service 中 (IServiceCollection)。

    Metrics
    程式碼 9~16 行,是用來設定 Metrics 相關資訊主要執行程式碼如下
    builder.Services.AddOpenTelemetry()
    	.WithMetrics(metrics =>
    	{
    		metrics.AddAspNetCoreInstrumentation()
    			   .AddHttpClientInstrumentation()
    			   .AddProcessInstrumentation()
    			   .AddRuntimeInstrumentation();
    	})
    
    AddOpenTelemetry() 是 IServiceCollection 的擴充方法,在這擴充方法中允許在 IServiceCollection 的 instance 直接使用,並在 service 中新增 TelemetryHostedService 的服務 (DI Lifecycle 同樣為 Singleton),最後方法回傳 OpenTelemetryBuilder 實例。並調用其 WithMetrics 方法,我們來看看該方法做了哪些事情
    /// 
    /// Adds metric services into the builder.
    /// 
    /// 
    /// Notes:
    /// 
    /// This is safe to be called multiple times and by library authors.
    /// Only a single  will be created for a given
    /// .
    /// This method automatically registers an  named 'OpenTelemetry' into the .
    /// 
    /// 
    /// The supplied  for chaining
    /// calls.
    public OpenTelemetryBuilder WithMetrics()
        => this.WithMetrics(b => { });
    
    /// 
    /// Adds metric services into the builder.
    /// 
    /// 
    /// 
    /// configuration callback.
    /// The supplied  for chaining
    /// calls.
    public OpenTelemetryBuilder WithMetrics(Action configure)
    {
        OpenTelemetryMetricsBuilderExtensions.RegisterMetricsListener(
            this.Services,
            configure);
    
        return this;
    }
    
    透過上述代碼我們可以得知下列資訊
    • WithMetrics 是 OpenTelemetryBuilder 的擴充方法,用於在 .NET 應用程式中加上 Metrics 中的標準服務 (Builder)
    • 方法一的 WithMetrics() 沒有參數,第二個 WithMetrics(Action configure) 接收一個參數 configure,用於將 Metrics 度量標準服務添加到建構器中
    • 內部調用 RegisterMetricsListener 來執行實際的註冊跟配置

    接者在回到 sample 專案程式碼中可以看到 WithMetrics 有四個設定值分別是 AddAspNetCoreInstrumentationAddHttpClientInstrumentationAddProcessInstrumentationAddRuntimeInstrumentation,透過上述程式碼可以蒐集應用程式的內建指標包括 Process、Memory、GC、HttpClient 與伺服器相關指標等資訊。提供開發者可以使用簡單幾行程式簡化啟用所有內建重要指標的過程,因此可以呼應上面在介紹 .NET Aspire Dashboard 時為何可以蒐集到這麼多與應用程式相關的 metrics 資訊,就是在這段程式碼所設定的才可以在 dashboard 看到。 如果對於 ASP.NTE Core Metrics 有興趣探索可以參考 built in metrics aspnetcore

    Traces
    程式碼 17~28 行,是用來設定 Traces 相關資訊主要執行程式碼如下
    .WithTracing(tracing =>
    {
        if (builder.Environment.IsDevelopment())
        {
            // We want to view all traces in development
            tracing.SetSampler(new AlwaysOnSampler());
        }
    
        tracing.AddAspNetCoreInstrumentation()
               .AddGrpcClientInstrumentation()
               .AddHttpClientInstrumentation();
    });
    
    並調用其 WithTracing 方法,我們來看看該方法做了哪些事情
    /// 
    /// Adds tracing services into the builder.
    /// 
    /// 
    /// Note: This is safe to be called multiple times and by library authors.
    /// Only a single  will be created for a given
    /// .
    /// 
    /// The supplied  for chaining
    /// calls.
    public OpenTelemetryBuilder WithTracing()
        => this.WithTracing(b => { });
    
    /// 
    /// Adds tracing services into the builder.
    /// 
    /// 
    /// 
    /// configuration callback.
    /// The supplied  for chaining
    /// calls.
    public OpenTelemetryBuilder WithTracing(Action configure)
    {
        Guard.ThrowIfNull(configure);
    
        var builder = new TracerProviderBuilderBase(this.Services);
    
        configure(builder);
    
        return this;
    }
      
    與 withMetrics 相似,兩者都是 OpenTelemetryBuilder 的公開擴充方法。並且都是一個方法沒參數,第二個方法提供 config 設定參數,在 withTraces 中會給特定的 IServiceCollection 建立 TracerProvider。

    在回到前面程式碼,預設會希望在開發環境自動將 trace 資料蒐集起來,方便開發者在測試環境時可以捕捉相關資訊,因此有類似判斷當符合條件時將採集器設定為 AlwaysOnSampler
    • AddAspNetCoreInstrumentation : 加上與 ASP.NET Core 相關的 tracing 資訊,這有助於開發者追蹤 Web 應用程式的請求和回應。
    • AddGrpcClientInstrumentation : 加上 gRPC 使 gRPC 呼叫可以被追蹤。
    • AddHttpClientInstrumentation : 加上 HttpClient 相關的 tracing 資訊,它有助於追蹤 HTTP 客戶端請求。

    Exporters
    上面提到很多蒐集遙測數據資料的設定與方法,最後這些資料會蒐集到何處呢 ? 在程式後面第 30 行透過 builder.AddOpenTelemetryExporters() 方法設定 OpenTelemetry 加上一種或是多種的導出器(Exporter),設定完後將蒐集到的各項資訊透過 config 設定發送到各個後端系統,例如 Azure Monitor、 Prometheus、Jaeger、Zipkin、Elasticsearch、Grafana 等。從 source code 可以看到蒐集位置是透過 config 的 OTEL_EXPORTER_OTLP_ENDPOINT,我們可以在透過 dashboard 中的 resource 查看此 config 設定位置為何。
    補充 : 如果有需要調整可以過 config 中的設定來修改。

    小結
    以上快速介紹了關於 .NET Aspire 提供好用的框架 dashboard,除了功能介紹之外也一起探索了其背後關於可觀測性三支柱 logging、Tracing、Metrics 在 .NET Aspire 的實現背後原理與程式碼說明。相信透過今天的文章各位夥伴對於 .NET Aspire dashboard 有更進一步的理解,身為開發者的我們在了解後相信也可以在自己所開發的應用程式中加上相關好用的功能,但 .NET Aspire 與 .NET 8 對於 Cloud Native 所提供的強大功能不僅於如此,在下篇文章我們將再繼續介紹其他好玩的功能與講解背後程式碼原理,happy Coding !

    參考
    .NET Aspire documentation (Preview)

    2024年3月4日 星期一

    [NET] .NET Aspire From 0 To 1 : 快速入門

    前言
    .NET Conf 一直是微軟對開發者展示火力的重要來源之一,在今年 .NET Conf 2023 上 .NET 平台團隊的 PM Glenn condrin 與 David Flower 介紹新一代雲原生框架 .NET Asipre。在議程中 David Fowler Demo 使用 .NET Aspire 專案,讓開發者可以輕鬆開始使用 .NET Aspire 框架提升開發者的體驗,並增進生產力,並帶來所有雲原生可以帶來的遙測數據、可觀察性、可擴展性和靈活性。另外讓我覺得興奮的是 .NET 8 與 OpenTelemetry 的深度整合,對於開發者在實踐可觀測性上更是方便許多。
    自己在研究 Aspire 接著會預計整理成相關系列文章,這篇是研究 .NET Aspire 的系列文第一篇,這系列主要會分為幾篇分別是
    • .NET Aspire 快速入門 : 介紹 .NET Aspire 的基礎知識,包括其設計理念、主要功能
    • .NET Aspire 中的可觀測性 : 解釋 .NET Aspire 如何提供應用程式的可觀測性,包括如何蒐集遙測數據、監控和日誌記錄
    • .NET Aspire 整合 : 說明 .NET Aspire 如何與其他微軟雲服務(如 Azure)整合
    希望可以透過各種官網的文件與說明,加上自己的理解針對新一代 .NET Aspire 雲原生框架進行說明,讓有興趣的開發夥伴們可以更進一步了解對開發者帶來的好處與效益,與若對於上述內容有問題或是不清楚的地方,歡迎提出來一起討論。


    背景
    近幾年互聯網發展的速度可以說是有增無減,新的科技名詞層出不窮,當中 ABCDE 可以代表新興科技發展的五個重要方向,分別是指 AI(人工智慧)、Big data(大數據)、Cloud(雲端)、Device(裝置)、Ecosystem(生態)。隨著雲端技術的成熟,將應用程式上雲一直是這幾年熱度不減的議題之一,身為開發者的我們,除了要了解或熟悉雲端上的服務 Service、將應用程式服務容器化,在 Cloud Native 雲原生概念出現後,開發者要將傳統的應用程式搬遷到雲端上也是一個不容忽視的挑戰,在 CNCF 雲原生基金會所提供各式各樣的 Gituhb 專案中,開發者可以找到許多用於建購或部署雲原生服務的工具或組件。這些組件或工具包含了架構、容器化、持續集成或是持續部署(CI/CD),在到上線後的監控與日誌等方面,身為開發者的我們,還須了解它們各自的優勢與限制將其組合起來,應用在開發專案中,有沒有一個框架可以協助開發者快速進度入雲原生應用 ? 讓開發者可以更專注的在開發應用程式的服務呢 ?

    .NET Aspire 簡介
    在官方 github 介紹如下
    .NET Aspire is an opinionated, cloud ready stack for building observable, production ready, distributed applications. .NET Aspire is delivered through a collection of NuGet packages that handle specific cloud-native concerns. Cloud-native apps often consist of small, interconnected pieces or microservices rather than a single, monolithic code base. Cloud-native apps generally consume a large number of services, such as databases, messaging, and caching.
    
    簡單翻譯可以理解為
    • .NET Aspire 是微軟為雲原生應用開發推出的一個新框架,它在 .NET 8 中提供了許多重要功能,專注於提升開發效率和簡化雲原生應用的開發過程。它包含了與雲端服務更緊密的整合,以及支持容器化、微服務架構和分散式系統管理的先進工具和實踐。
    .NET Aspire 的目標是簡化複雜的雲原生應用開發,同時提供強大的功能,如改進的遙測數據、可觀察性、可擴展性和靈活性。這對於追蹤和管理分散式系統至關重要,尤其是在面對快速發展的雲端環境時。

    準備條件
    了解完 .NET Asipre 想要解決的問題與目的後,接著我們來看如果想要使用 .NET Aspire 的前置作業是甚麼,在使用前需安装以下軟體:
    • .NET 8.0
    • .NET Aspire workload
    • Use the Visual Studio installer
    • Use the dotnet workload install aspire command
    • Docker Desktop
    • Integrated Developer Environment (IDE) or code editor, such as:
    • Visual Studio 2022 Preview version 17.9 or higher (Optional)
    • Visual Studio Code (Optional)
    透過 cli 安裝 .NET Aspire workload 示意圖
    Use the Visual Studio installer,記得確認右方要有 .NET Aspire SDK (Preview)
    建立專案
    在本機安裝完上述的軟體後,接著我們透過 Visual Studio IDE 來建立 Aspire 應用程式模板方案,在 Visual Studio 2022 17.9 版本有提供 .NET Aspire 專案模板,可以提供開發者設定出初始組態設定作業。

    Step 1 : 開啟 Visual Studio 並建立新專案,右方對話框中搜尋 Aspire 後選擇或者是在 project type 直接選擇 .NET Aspire,點選 .NET Aspire Starter Application,點選下一步
    Step 2 : 專案名稱輸入 AspireSampleApp,其餘設定保持預設值,點選下一步
    Step 3 : Framework 選擇 .NET 8(Long term support),接著按下建立按鈕
    創建完畢之後,我們來看一下方案中預設有哪些專案跟內容
    └───📂 AspireSample
         ├───📂 AspireSample.ApiService
         │    ├───📂 Properties
         │    │    └─── launchSettings.json
         │    ├─── appsettings.Development.json
         │    ├─── appsettings.json
         │    ├─── AspireSample.ApiService.csproj
         │    └─── Program.cs
         ├───📂 AspireSample.AppHost
         │    ├───📂 Properties
         │    │    └─── launchSettings.json
         │    ├─── appsettings.Development.json
         │    ├─── appsettings.json
         │    ├─── AspireSample.AppHost.csproj
         │    └─── Program.cs
         ├───📂 AspireSample.ServiceDefaults
         │    ├─── AspireSample.ServiceDefaults.csproj
         │    └─── Extensions.cs
         ├───📂 AspireSample.Web
         │    ├───📂 Components
         │    │    ├───📂 Layout
         │    │    │    ├─── MainLayout.razor
         │    │    │    ├─── MainLayout.razor.css
         │    │    │    ├─── NavMenu.razor
         │    │    │    └─── NavMenu.razor.css
         │    │    ├───📂 Pages
         │    │    │    ├─── Counter.razor
         │    │    │    ├─── Error.razor
         │    │    │    ├─── Home.razor
         │    │    │    └─── Weather.razor
         │    │    ├─── _Imports.razor
         │    │    ├─── App.razor
         │    │    └─── Routes.razor
         │    ├───📂 Properties
         │    │    └─── launchSettings.json
         │    ├───📂 wwwroot
         │    │    ├───📂 bootstrap
         │    │    │    ├─── bootstrap.min.css
         │    │    │    └─── bootstrap.min.css.map
         │    │    ├─── app.css
         │    │    └─── favicon.png
         │    ├─── appsettings.Development.json
         │    ├─── appsettings.json
         │    ├─── AspireSample.Web.csproj
         │    ├─── Program.cs
         │    └─── WeatherApiClient.cs
         └─── AspireSample.sln
    
    稍早建立的方案 AspireSampleApp 其中有內建四個專案,分別是
    • AspireSampleApp.ApiService
    • AspireSampleApp.AppHost
    • AspireSampleApp.ServiceDefaults
    • AspireSampleApp.Web
    接著我們來針對這些重要的專案分別作重點介紹

    AppHost
    做為跨專案的協調器 (orchestrator) 項目,用於連結和配置應用程式不同項目和服務。此專案會設定為方案的啟動項目,並且依賴於 AspireSample.ApiService 和 AspireSample.Web 專案。專案命名以 *.AppHost 做結尾,且開啟專案屬性的設定為 true
    前面提到 AppHost 專案作為協調器,那麼在這專案要如何設定呢 ? 我們可以開啟 AspireSampleApp.AppHost 中的 Program.cs 程式碼來一探究竟
    var builder = DistributedApplication.CreateBuilder(args);
    
    var cache = builder.AddRedis("cache");
    
    var apiService = builder.AddProject("apiservice");
    
    builder.AddProject("webfrontend")
        .WithReference(cache)
        .WithReference(apiService);
    
    builder.Build().Run();
    
    • 以上代碼開始透過 CreateBuilder 方法建立 IDistributedApplicationBuilder 的 instance,透過 IDistributedApplicationBuilder 的擴充方法來設定其相依資源 (resource)
    • 程式碼中描述定義包含三個資源 (resource),要設定 Redis 快取就是透過 .AddRedis 擴充方法並設定其容器 (Container) 名稱是 Cache
    • 接著加入兩個專案 (Project) 分別是 apiservice 跟 webfrontend,因此使用 AddProjects 方法來將 project 加入到 AppHost 專案中
    • WithReference 方法是動態注入 service discovery 的一部分,將其資訊 endpoint 注入到應用程式的配置或資源中,使得在運行時可以根據配置或環境進行適當的連結,查看 source code 可以發現其 format 是 "services__{sourceResourceName}__{endpointIndex}={endpointNameQualifiedUriString}。
    • 使用 Build.Run() 方法來啟動應用程式與所有相依性
    MSDN 有針對各自用途做詳細介紹並整理成可視化的圖形如下
    另外也提供多種資源類型,像是 ProjectResource、ContainerResource 和 ExecutableResource,詳細可以參考 app-host-overview 介紹

    ServiceDefaults
    ServiceDefaults 專案目的是放置共用的項目。

    過去在開發雲原生應用程式時,遇到好用的 package 或是套件時可以說是每個專案都會同步加上,例如像是 log 可能會使用 serilog 搭配合適的 skin,如果想要加上 retry 機制可能會加上 polly 等廣為人知的好用套件,但如果應用程式的架構或是服務拆分越來越細時,這些套件會在各個專案都重複看見與被使用,假設其套件的組態設定需要調整時,也需要在各個所使用的專案上進行調整,才有機會將其設定統一設定好不遺漏。這可以說是開發者不方便的點之一,在 .NET Aspire 中為了解決這問題,提供開發者可以將其設定移置 serviceDefault 專案中,來提供開發者更好的開發體驗,也可以在其專案中加上工具、OpenTelemetry 狀態檢查獲是環境變數等管理。
    以 AspireSampleApp 專案為例建立完後會有 AspireSampleApp.Web 與 AspireSampleApp.ApiService 等應用程式專案,兩者其共用的組態設定與配置是定義在 AspireSampleApp.ServiceDefaults 的 AddServiceDefaults 擴充方法中。程式碼如下
    public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder)
    {
        builder.ConfigureOpenTelemetry();
    
        builder.AddDefaultHealthChecks();
    
        builder.Services.AddServiceDiscovery();
    
        builder.Services.ConfigureHttpClientDefaults(http =>
        {
            // Turn on resilience by default
            http.AddStandardResilienceHandler();
    
            // Turn on service discovery by default
            http.UseServiceDiscovery();
        });
    
        return builder;
    }
    
    • ConfigureOpenTelemetry 方法 : 用來設定 openTelemetry 收集遙測數據的設定
    • AddDefaultHealthChecks 方法 : 定義應用程式 healthcheck (AddCheck 方法) 服務正常時需要回傳的值
    • AddServiceDiscovery 方法 : 新增 service discovery 功能
    • ConfigureHttpClientDefaults : 新增在使用 httpClient 的預設值
    ApiService 與 Web
    • ApiService : 隨機回傳氣溫結果
    • Web : 作為 Client 負責呼叫 apiService 並將請求呈現在網頁上
    目的是演示 Demo 用的氣溫應用程式,若有興趣可以查看專案內容,在此就不在多介紹說明

    測試專案
    在上面的描述與說明中我們可以初步了解 .NET Aspire sample project 方案中各自專案的用途,設定 AspireSampleApp.Web 為起始專案後,在 Visual Studio 按下 F5 來執行應用程式,可以看到天氣的頁面
    專案啟動時同步也會啟動 .NET Aspire 儀表板示意圖如下
    今天快速介紹了關於微軟推出的新框架 .NET Aspire,以及透過 Visual Studio IDE 建立 .NET Aspire 新專案的過程,也探索了其方案建立後專案的組成與各自的設計含意與目的,相信透過今天的文章對於 .NET Aspire 有了初步的認識,.NET 8 整合 openTelemetry 後將其遙測數據收集到 .NET Aspire 所提供的 Dashboard 上,讓開發者對於應用程式的掌握度更高,下一篇我們再來探索 .NET Aspire 儀錶板其奧妙之處 !


    參考
    .NET Aspire documentation (Preview)

    2024年2月9日 星期五

    [Free] 電子書 : Observability 101

    前言
    在國外,可觀測性 (Observability) 這個詞已經成為熱門話題引起熱烈討論,在 CNCF (Cloud Native Computing Foundation) landscape 中有一個區域專門介紹可觀測性 (Observability) 相關工具與技術。 在國外研討會中,發現越來越多人探討如何透過可觀測性來實現 DevOps 更高效率。 近幾年台灣也開始看到越來越多相關文章與研討會分享,分享有關可觀測性的觀念與實踐經驗。在吸收這些知識與寶貴知識後,對這主題有更深入的了解與認識。因此希望自己可以藉由 ITHome 鐵人賽的機會,整理並分享自己關於可觀測性的理解與小小心得。希望藉由透過這次不要臉分享,可以讓對這主題也有興趣的朋友們能夠更快了解可觀測性的重要觀念,一起入坑。

    參加鐵人賽完賽後將此參加過程的技術文章整理後放置在 github 上,並統整成 pdf 電子檔方便提供給有需要的人下載。

    此書章節如下
    • 第 01 天 : 起心動念
    • 第 02 天 : Observability in DevOps
    • 第 03 天 : Business Continuity
    • 第 04 天 : Service Level Agreement
    • 第 05 天 : Disaster Recovery
    • 第 06 天 : 災難復原計畫 Disaster Recovery Plan
    • 第 07 天 : 高可用性與可靠性 High Availability & Reliability
    • 第 08 天 : 監控與指標分析 Monitor
    • 第 09 天 : DevOps x Observability 小結
    • 第 10 天 : 可觀測性 Observability
    • 第 11 天 : 解析監控和可觀測性:從哨塔到全景地圖
    • 第 12 天 : 可觀察性的演進史:從控制理論到重新定義
    • 第 13 天 : 可觀測性信號(Signals)的進化之旅
    • 第 14 天 : 可觀測性管道:解析現代數據收集與分析
    • 第 15 天 : 開賽至今的回顧與反思
    • 第 16 天 : 可觀測性與它的工具小夥伴們
    • 第 17 天 : OpenTelemetry : 在收集遙測數據中加上一點新標準
    • 第 18 天 : OpenTelemetry : 核心元件大解密 (1/2)
    • 第 19 天 : OpenTelemetry : 核心元件大解密 (2/2)
    • 第 20 天 : OpenTelemetry : Demo 專案快速入門 (1/2)
    • 第 21 天 : OpenTelemetry : Demo 專案快速入門 (2/2)
    • 第 22 天 : 可觀測性摘要 cheetsheet 及小結
    • 第 23 天 : 可觀測性工具的整合與挑戰
    • 第 24 天 : Grafana Cloud : 雲端監控的未來
    • 第 25 天 : Grafana Cloud : 蒐集應用程式遙測數據
    • 第 26 天 : Grafana Cloud : 蒐集應用程式遙測數據 (2/2)
    • 第 27 天 : Grafana Cloud : 使用 Grafana Pyroscope 優化應用程式性能
    • 第 28 天 : Grafana 事件管理 : 從告警到修復的問題排除流程 (1/2)
    • 第 29 天 : Grafana 事件管理 : 從告警到修復的問題排除流程 (2/2)
    • 第 30 天 : 從傳統開發到可觀測性驅動開發 (ODD)
    • 第 31 天 : 30 天之後 ?

    如何取得電子書
    基於「取之網路,用之網路」的精神,此電子書是免費的,如果您喜歡這本電子書或者它對您有幫助,請您高抬貴手在 GitHub 電子書項目專案給我一些鼓勵 ⭐️⭐️⭐️ : 傳送門

    Copyright © m@rcus 學習筆記 | Powered by Blogger

    Design by Anders Noren | Blogger Theme by NewBloggerThemes.com