koudenpaのブログ

趣味のブログです。株式会社はてなでWebアプリケーションエンジニアをやっています。職業柄IT関連の記事が多いと思います。

.NET で動くアプリケーションを Mackerel で監視できるかな?

Mackerel Advent Calendar 2018 - Qiita の2日目の記事は以下のようなものでした。

qiita.com

かっこいい。Javaうらやましい。.NET向けに同様な物はないかな? とググったところ App Metrics というメトリック収集ライブラリがありました。

公式には GrafanaCloud, Prometheus, Elasticsearch, Graphite などがサポートされているようです。

サードパーティDatadog向けのフォーマッター もありました。

「こいつは面白そうだ」ということで、Mackerelにもメトリクスをレポートしてみました。

続きを読む

ASP.NET Core の ConfigurationBuilder の構成順に気を付ける

ASP.NET Core では ConfigurationBuilder を使用してアプリケーションの設定を構成する。

ただ、あまりこれを自分で呼び出すことはなく、大体はデフォルト構成で済んでしまう。 その場合はいい感じに構成される。

特別な事情があって自分で構成する場合は、構成メソッドの呼び出しに注意する。 同一のキーの設定値があった場合、後に呼び出した構成メソッドで値が上書きされていく。

私はこのような順で構成し、設定ファイル( appsettings.json )のダミー値が採用されました。

var config = new ConfigurationBuilder()
    .AddCommandLine(args)
    .AddEnvironmentVariables()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
    .Build();

実行時引数 < 環境変数 < 設定ファイル の順(強さ)で適用される。 逆だろ! 普通!!

尚、無意識に使うASP.NET Coreのデフォルト構成はこのような感じでした。 完璧ですね。

.ConfigureAppConfiguration((hostingContext, config) =>
{
    var env = hostingContext.HostingEnvironment;

    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
          .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

    if (env.IsDevelopment())
    {
        var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
        if (appAssembly != null)
        {
            config.AddUserSecrets(appAssembly, optional: true);
        }
    }

    config.AddEnvironmentVariables();

    if (args != null)
    {
        config.AddCommandLine(args);
    }
})

ドキュメントに解説もあります。

ASP.NET Core の Web ホスト | Microsoft Docs

次の順序でアプリの構成を読み込みます。 - appsettings.json。 - appsettings.{Environment}.json。 - エントリ アセンブリを使用して Development 環境でアプリが実行される場合に使用されるシークレット マネージャー。 - 環境変数。 - コマンド ライン引数。

このBlogでは何度も書いていますが、みなさん「ドキュメントはしっかり読みましょう」。それでは。

Swagger で広がるような気がする Mackerel の世界

元々はよい感じに試行を行って『Swagger で広がる Mackerel の世界』のような景気の良いタイトルにしようと思ったのですが、なかなか辛みもあったので弱気なタイトルになりました。本記事は Mackerel Advent Calendar 2018 の4日目の記事です。

さて、Mackerelは近年のSaaSでは標準装備となっているHTTPで呼び出せるAPIの提供が行われています。

Mackerelの機能は公式の mackerel-agent も含めてほぼすべてがこのAPIを活用しています。 (Webコンソールは違う様子です。そもそも認証がAPI Keyではないですからね)

このHTTPで呼び出せるAPIには定義の仕様が存在しており、その中の一つがSwaggerです。 現在はSwaggerの後継のOpenAPI Specificationが最新なのですが、周辺エコシステムの整備状況から2018年末現在ではSwaggerを使用するのが現実的な状況です。

さて、そのSwaggerによるMackerel APIの仕様定義があるとどうなるのか? を見てみたいと思います。

サンプルはSwaggerを良い感じに活用している気がする Azure の Logic Apps です。

定義は自分がMackerelを使うときのサンプルにしている『アラートの数をサービスメトリックに投稿する』事ができる最低限のAPIに対して行いました。

open-api-spec-sandbox/mackerel-api.yml at master · 7474/open-api-spec-sandbox · GitHub

続きを読む

閉じたアラートも取れるようになったMackerelのAPIで勤怠を得んと欲す

月末ですね。

Mackerelアドベントカレンダーが明日から始まりますが、この試行は月末に価値があるので自称0日目の記事として書きます。

さて、みなさん、勤怠の記録は毎日つけていますか? 自分はまぁ、言わぬが華です。

Google MapのLogで毎日何時頃にオフィスにIn/Outしているのかを月末にチェックしているような人もいるようです。面倒くさいですね。

さて、Mackerelユーザーの作業用端末には当然 mackarel-agent が入っています。であるならば、閉じたアラートも取れるようになったMackerelのAPIでその電源On/Off時間(デフォルトで構成される connectivity アラート!)を得ることができます。これは相当に正確な出退勤時間ではないでしょうか?

前置きが長いですね。試しました。

mkr コマンドと jq コマンドの合わせ技です。

$ HOSTID=YOURHOSTID
$ mkr alerts -w | jq -r ".[] | select((.type == \"connectivity\") and (.hostId == \"$HOSTID\")) | [(.openedAt|tonumber|.+32400|todate), (.closedAt|tonumber|.+32400|todate)] | @csv"
"2018-11-30T09:52:03Z","2018-11-30T09:55:26Z"
"2018-11-30T06:31:03Z","2018-11-30T09:45:50Z"
"2018-11-30T04:54:03Z","2018-11-30T06:25:14Z"
"2018-11-30T01:18:03Z","2018-11-30T04:48:36Z"
"2018-11-29T23:30:04Z","2018-11-30T01:12:17Z"
"2018-11-29T21:42:03Z","2018-11-29T23:24:23Z"
"2018-11-29T20:37:04Z","2018-11-29T21:36:23Z"
"2018-11-29T19:59:04Z","2018-11-29T20:31:22Z"
"2018-11-29T19:43:04Z","2018-11-29T19:43:23Z"
"2018-11-29T19:24:03Z","2018-11-29T19:26:35Z"
"2018-11-29T13:21:03Z","2018-11-29T13:28:52Z"
"2018-11-29T11:11:03Z","2018-11-29T11:13:08Z"
"2018-11-29T10:04:03Z","2018-11-29T10:09:36Z"
"2018-11-28T21:02:03Z","2018-11-29T09:46:59Z"
"2018-11-28T18:20:03Z","2018-11-28T19:01:07Z"

結果を見てみましょう。

"2018-11-30T09:52:03Z","2018-11-30T09:55:26Z" <- 身に覚えがない
"2018-11-30T06:31:03Z","2018-11-30T09:45:50Z" <- Close=出勤時間
"2018-11-30T04:54:03Z","2018-11-30T06:25:14Z" <- なにこれ
"2018-11-30T01:18:03Z","2018-11-30T04:48:36Z" <- なにこれ
"2018-11-29T23:30:04Z","2018-11-30T01:12:17Z" <- なにこれ
"2018-11-29T21:42:03Z","2018-11-29T23:24:23Z" <- なにこれ
"2018-11-29T20:37:04Z","2018-11-29T21:36:23Z" <- Open=退勤時間(社内で懇親会していたので少し遅い
"2018-11-29T19:59:04Z","2018-11-29T20:31:22Z" <- 階移動時のWi-Fi切れ
"2018-11-29T19:43:04Z","2018-11-29T19:43:23Z" <- 接続切れすぎ
"2018-11-29T19:24:03Z","2018-11-29T19:26:35Z" <- 接続切れすぎ
"2018-11-29T13:21:03Z","2018-11-29T13:28:52Z" <- 覚えてない
"2018-11-29T11:11:03Z","2018-11-29T11:13:08Z" <- 覚えてない
"2018-11-29T10:04:03Z","2018-11-29T10:09:36Z" <- 覚えてない
"2018-11-28T21:02:03Z","2018-11-29T09:46:59Z" <- 綺麗に勉強会終了〜出勤時刻が出てる!
"2018-11-28T18:20:03Z","2018-11-28T19:01:07Z" <- Open=退勤、Close=勉強会場でWi-Fi接続、この日にエージェント入れた

うーむ。微妙。思った以上にノイズが多かったです。

とはいえ、自分にとってはとても参考になる確実なデータを得られました。

今後活用する機会がありそうです。

それでは皆さん、Mackerelと一緒によい社会生活を!

Node-RED UG勉強会 2018 年末LTパーティ

node-red.connpass.com

でLTをしてきた。

LT本数が10本と多く、かつ内容のバリエーションも豊富で非常に良いエネルギーを得られる勉強会だった。

自分のLTスライドはこちら。

www.slideshare.net

以前UGの勉強会に参加した際に発表内容が応用に寄っていた感じを受けたので、Node-REDをより活用するための入り口になればいいなぁ、といった動機でテーマを選んだ。

するとどうだろう? 同じようなことを考えたのかどうかは別として、同様なテーマのLTをする方がいらっしゃった。 「大事なことなので2LTで取り上げました」「参照URLまで同じ」などなかなか得がたいオモシロ体験だった。 (懇親会でも笑いながらそのLTをされた方と話させてもらった)

とはいえ、切り口はだいぶ違ったのでNode作成への入門としてはむしろ良かったのではないかと思う。

「参考になった」「Nodeを作ってみたくなった」と言った感想ももらえてとても嬉しかった。

なお「カスタムNode」という言葉は自分の造語だった様子。 どこかで見かけた気がしたのだけれど、そんなことはなかった。 困ったもんだ。

いろんな笑いと知見を得られたLT会だった。


同様テーマだった方のLTスライド。

www.slideshare.net

クソワロタ。


12-03追記:

主催の一人である 1ft_seabass さんがトゥギャってくださっている。当日の空気感はそちらで確認できる。

Entity Framework Core 2.0 でASP.NET Core起動時にマイグレーションする

こんな感じの Program.cs にすることでとりあえず実現できた。

ただ、この手法はシングルインスタンスのアプリケーションでの適用に限定しておいた方が良さそうだ。

 class Program
{
    public static void Main(string[] args)
    {
        var host = BuildWebHost(args);

        // 起動時にDBマイグレーションを当てる
        UpdateDatabase(host);

        host.Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseApplicationInsights()
            .UseStartup<Startup>()
            .Build();

    private static void UpdateDatabase(IWebHost host)
    {
        // https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.1#call-services-from-main
        using (var serviceScope = host.Services.CreateScope())
        {
            var services = serviceScope.ServiceProvider;
            var logger = services.GetRequiredService<ILogger<Program>>();
            try
            {
                var dbContext = services.GetService<ApplicationDbContext>();
                dbContext.Database.OpenConnection();

                logger.LogInformation("Start database migration.");
                // https://docs.microsoft.com/ja-jp/ef/core/managing-schemas/migrations/#apply-migrations-at-runtime
                // Webアプリケーションではあまり推奨されていない様子。
                // 明確なマイグレーションタスクをデプロイパイプラインに含めるのが良いようだ。
                dbContext.Database.Migrate();
                logger.LogInformation("End database migration.");

            }
            catch (Exception ex)
            {
                logger.LogError(ex, "An error occurred.");
            }
        }
    }
}
続きを読む

Entity Framework Core 2.0 で CreatedAt UpdatedAt

自分はORMではS2JDBCの洗礼を浴びていて、静的な型がついているEntityをRDBにMappingしてくれるORMが好きだ。

最近ではEntity Framework Coreが良くて、ちょっと前から使っているシステムがある。

唐突にそれでやっている工夫を書きたくなったので書く。

タイトルの通りあるEntityの生成時刻と更新時刻をアプリケーションプログラムで付与するものだ。

確認してみたらバージョンは 2.0.x だった。2つほどマイナーバージョンを置いて行かれている。大分変っているのだろうなぁ。

続きを読む