Rustで複数のbinをおいたときに function foo is never usedの警告がでないようにする

Rustの1つのcargoプロジェクトで、src/bin以下に複数のbinをおいていたが、いろいろな関数でfunction foo is never usedという警告が出てしまっていた。 もちろん#[allow(dead_code)]って関数やファイルの先頭に書けば警告は出なくなるのだが、dead_code検出自体は便利なので、むやみに抑制しないようにしたい。rust-analyzerが出す警告だと思うので、コンパイルに関するなにかだろうと思って、うまくやって警告そのものが出ないようにできないか調べた。

AI(OpenAI 4o)だとプロンプトにも問題があったかもしれないがうまく答えてくれなかったが、stackoverflowに参考になる答えがあった。

rust - Dead code warning with multiple binaries? - Stack Overflow

つまり、複数のbinがあるということは複数回コンパイルが走るので、そのうちのどれかから参照されていないとdead_code扱いになるということのようだ。 それを防ぐためには、呼び出すコードはlib.rsに集約してそれぞれのbinはそこから呼び出せばよい。

Streamlitでは、st.session_state.my_key = st.session_state.my_key というコードに意味がある

Streamlitのドキュメントを読んでたら、以下のコードが出てきた。

st.session_state.my_key = st.session_state.my_key

Widget behavior - Streamlit Docs

同じ変数に同じ変数を代入するっていうのに強烈な違和感を持った。 普通のプログラミングなら、まず無駄なコードってなるやつだ。 現に、Copilotにリファクタリングを指示したら消す提案をしてきた。

この挙動を実際に動かして確かめてみて、意味が理解できたのでメモしておく。

以下の例で確認。

import streamlit as st

if "textbox_a" in st.session_state:
    st.session_state.textbox_a = st.session_state.textbox_a

st.session_state.setdefault("show_textbox", True)

if st.button("テキストボックス表示変更"):
    st.session_state.show_textbox = not st.session_state.show_textbox

if st.session_state.show_textbox:
    st.text_input(
        "テキストボックスA",
        key="textbox_a",
        value="テキストボックスAの初期値",
    )

「テキストボックス表示変更」っていうボタンがあって、それを押すと、テキストボックスAの表示が切り替わる。 テキストボックスAでは、key="textbox_a" としているので、 st.session_state.textbox_a に入力した値を状態保持する。

ただし、Widgetは非表示になってしまうと状態はリセットされる。つまり、

st.session_state.textbox_a = st.session_state.textbox_a の部分のコードが無いとき

ボタンを押してテキストボックスを非表示にした時点で状態はリセットされ、テキストボックスAの値は「テキストボックスAの初期値」になってしまう。

コードがあるとき

ボタンを押してテキストボックスを非表示にして再度表示にした場合でも、前回入力した値が保持されている。

S3にあるALBログの調査はAthenaよりDuckDBのほうが簡単

AWSのALB(Application Load Balancer)のログはS3に置かれるが、この中身をサクッと調べたいとき、Athenaを使う方法が標準的で、下記で案内されているようにパーティション射影(Partition Projection)でテーブルを作ってAthenaからクエリする。

パーティション射影を使用して Athena で ALB アクセスログ用テーブルを作成する - Amazon Athena

私も従来はその方法を使っていたが、Athenaはブラウザから使うと動作がもっさりしているし、決まったクエリを1回きり実行して結果を取得したいだけのときならまだしも、探索的にクエリを何発も実行したいときには使い勝手が悪い。

最近他のプロジェクトでDuckDBを使うようになって、使い勝手の良さに感動していたが、DuckDBはALBのログを探索的に調べたいときにもめっちゃ使えると思った。

DuckDBのインストールは公式 あたりを参照。S3のファイルをクエリする準備としてはAWS Extension – DuckDBS3 API Support – DuckDBを参照。 端的にいうと、シェルでS3にアクセスできるクレデンシャルの環境変数がロードされている状態でDuckDBを起動して、

INSTALL aws;
LOAD aws;
INSTALL httpfs;
LOAD httpfs;
CREATE SECRET (
    TYPE S3,
    PROVIDER CREDENTIAL_CHAIN
);

これでロードしてあるクレデンシャルがアクセス権限を持つS3のファイルに対してクエリできるようになる。 例えば2024年11月のログをロードするなら下記のようにする。Blobのパターンを変えれば任意の期間のデータをロードできる。 この定義にあたってはパーティション射影を使用して Athena で ALB アクセスログ用テーブルを作成する - Amazon Athena にある定義を参考にした。

CREATE TABLE alb_log_202411 AS
SELECT *
FROM read_csv(
    's3://[YOUR_S3_BUCKET_NAME]/AWSLogs/[YOUR_ACCOUNT_ID]/elasticloadbalancing/[YOUR_REGION]/2024/11/**/*.log.gz',
    columns={
        'type': 'VARCHAR',
        'timestamp': 'TIMESTAMP',
        'elb': 'VARCHAR',
        'client_ip_port': 'VARCHAR',
        'target_ip_port': 'VARCHAR',
        'request_processing_time': 'DOUBLE',
        'target_processing_time': 'DOUBLE',
        'response_processing_time': 'DOUBLE',
        'elb_status_code': 'INTEGER',
        'target_status_code': 'VARCHAR',
        'received_bytes': 'BIGINT',
        'sent_bytes': 'BIGINT',
        'request': 'VARCHAR',
        'user_agent': 'VARCHAR',
        'ssl_cipher': 'VARCHAR',
        'ssl_protocol': 'VARCHAR',
        'target_group_arn': 'VARCHAR',
        'trace_id': 'VARCHAR',
        'domain_name': 'VARCHAR',
        'chosen_cert_arn': 'VARCHAR',
        'matched_rule_priority': 'VARCHAR',
        'request_creation_time': 'TIMESTAMP',
        'actions_executed': 'VARCHAR',
        'redirect_url': 'VARCHAR',
        'error_reason': 'VARCHAR',
        'target_port_list': 'VARCHAR',
        'target_status_code_list': 'VARCHAR',
        'classification': 'VARCHAR',
        'classification_reason': 'VARCHAR',
        'conn_trace_id': 'VARCHAR'
    },
    delim=' ',
    quote='"',
    escape='"',
    header=False,
    auto_detect=False
);

S3の対象ファイル数が多い場合テーブルができるまでにそこそこ時間はかかるが、いったんローカルにロードされればあとは速い。

  • テーブルの存在を確認
D show tables;
┌────────────────┐
│      name      │
│    varchar     │
├────────────────┤
│ alb_log_202411 │
└────────────────┘
D describe alb_log_202411;
┌──────────────────────────┬─────────────┬─────────┬─────────┬─────────┬─────────┐
│       column_name        │ column_type │  null   │   key   │ default │  extra  │
│         varchar          │   varchar   │ varchar │ varchar │ varchar │ varchar │
├──────────────────────────┼─────────────┼─────────┼─────────┼─────────┼─────────┤
│ type                     │ VARCHAR     │ YES     │         │         │         │
│ timestamp                │ TIMESTAMP   │ YES     │         │         │         │
│ elb                      │ VARCHAR     │ YES     │         │         │         │
│ client_ip_port           │ VARCHAR     │ YES     │         │         │         │
│ target_ip_port           │ VARCHAR     │ YES     │         │         │         │
│ request_processing_time  │ DOUBLE      │ YES     │         │         │         │
│ target_processing_time   │ DOUBLE      │ YES     │         │         │         │
│ response_processing_time │ DOUBLE      │ YES     │         │         │         │
│ elb_status_code          │ INTEGER     │ YES     │         │         │         │
│ target_status_code       │ VARCHAR     │ YES     │         │         │         │
│ received_bytes           │ BIGINT      │ YES     │         │         │         │
│ sent_bytes               │ BIGINT      │ YES     │         │         │         │
│ request                  │ VARCHAR     │ YES     │         │         │         │
│ user_agent               │ VARCHAR     │ YES     │         │         │         │
│ ssl_cipher               │ VARCHAR     │ YES     │         │         │         │
│ ssl_protocol             │ VARCHAR     │ YES     │         │         │         │
│ target_group_arn         │ VARCHAR     │ YES     │         │         │         │
│ trace_id                 │ VARCHAR     │ YES     │         │         │         │
│ domain_name              │ VARCHAR     │ YES     │         │         │         │
│ chosen_cert_arn          │ VARCHAR     │ YES     │         │         │         │
│ matched_rule_priority    │ VARCHAR     │ YES     │         │         │         │
│ request_creation_time    │ TIMESTAMP   │ YES     │         │         │         │
│ actions_executed         │ VARCHAR     │ YES     │         │         │         │
│ redirect_url             │ VARCHAR     │ YES     │         │         │         │
│ error_reason             │ VARCHAR     │ YES     │         │         │         │
│ target_port_list         │ VARCHAR     │ YES     │         │         │         │
│ target_status_code_list  │ VARCHAR     │ YES     │         │         │         │
│ classification           │ VARCHAR     │ YES     │         │         │         │
│ classification_reason    │ VARCHAR     │ YES     │         │         │         │
│ conn_trace_id            │ VARCHAR     │ YES     │         │         │         │
├──────────────────────────┴─────────────┴─────────┴─────────┴─────────┴─────────┤
│ 30 rows                                                              6 columns │
└────────────────────────────────────────────────────────────────────────────────┘

あとはいろいろクエリしてお好きなように。

  • select * from alb_log_202411 where elb_status_code != 200 LIMIT 1;
  • select timestamp, request, elb_status_code, target_status_code, domain_name from alb_log_202411 where elb_status_code != 200 LIMIT 100
  • select timestamp, request, elb_status_code, target_status_code, domain_name from alb_log_202411 where elb_status_code != 200 and domain_name != 'foobar.com' LIMIT 100

みたいに探索的に調べるのが高速にやれるのが最高。

※補足

30カラムもあるので、デフォルトではコマンドラインで全部のカラムを表示できない。 なので、SELECT句でカラムを絞るか、 .mode line とか .mode box とかで全カラム表示できる。 デフォルトに戻すには .mode duckbox。 どういう選択肢があるかはOutput Formats – DuckDB見ると分かる。

※補足2

ググったら似たことしている記事あったのでリンクしとく

Analysing AWS Application Load Balancer Logs with DuckDB: Unleashing Performance Insights

Rustのglibc依存問題

Rustはコンパイルできれば動くと思いきや、そうでもない。 cargo-lambdaを使って、ローカル環境で動作確認したlambda関数をデプロイしたら、動かなかった。

/var/task/bootstrap: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by /var/task/bootstrap)`

Amazon Linux2(AL2)とAmazon Linux2023(AL2023)のそれぞれのglibcのバージョンは ツールチェーンの改善: gcc、binutils、 glibc - Amazon Linux 2023 に記載のとおり、2.26, 2.34なので、AL2だとエラーが出たということだった。AL2023でデプロイしなおしたら問題なく動いた。

aws-lambda-rust-runtimeのREADMEを見ると al2023を使うことを勧めている。

この記事もみつけた。 cargo lambda deployした関数が `GLIBC_2.28' not found でうごかない

ビルド時に--target を指定することで解決できるようだ。

cargo lambda build --release --target aarch64-unknown-linux-gnu.2.26

下記の記事ではいろいろな選択肢がリストアップされているが、結局のところどれが良いかはアプリの実装内容や、環境や運用の方法によって異なりそう。

Rust でバイナリを配布する

時系列+もう一つの何らかの属性で検索することがほとんどのデータは、S3に置いてs3 selectが有用

www.infoq.com

この記事が話題になってて( なお元記事はここっぽい Moving from DynamoDB to tiered storage with MySQL+S3 | by Shane Hender | Zendesk Engineering )、かつて似たことやってAWS Summit Tokyoのミニステージで登壇したことがあったので忘れないうちに補足記事を書こうと思った。

www.nileworks.co.jp

PDFファイルの直接のリンクは以下になる。

ドローン運行監視 ーAmazon AthenaのBucketingとAmazon S3 Selectの活用ー

このスライドの概要としては、S3に保存されているドローンの飛行ログデータを、AthenaのCTAS + Bucketingを使って1日1回任意のまとまりでS3のファイルを適切な階層構造に配置しなおし、APIサーバーから取得できるようにしたという事例紹介となる。

この場合は飛行ログなので、機体のIDと、時系列で検索できればほとんどの場合十分だ。 このように時系列+何らかの属性のみで検索することがほとんどのデータがけっこうたくさんあると思っていて、そういうときにはこのパターンは適していると思う。

S3でファイルを置くならFirehoseとかで事足りそうに思うかもしれないが、Firehoseでファイルを置くとファイル数が増えてしまうので、そのままではS3 selectでクエリするのに適さないので、適切な粒度でファイルをまとめなおすという一手間を加えている。

このシステムでは実際にこの仕組みを使って、フロントエンドのNext.jsから、APIサーバーに任意の機体の任意の時間の飛行ログを問い合わせる仕組みを作って、過去の飛行履歴をすべて振り替えれるようにしている。

S3はExpress One Zoneもリリースされたので、より高速にレスポンスするようになっただろうから、S3はデータストレージとして更に有望になったと思う。システム要件によるが、REST APIなどでS3に置いたデータをクエリしてレスポンスするといったことは十分現実的だと思う。

最近はDuckDBに注目している。これもS3にあるログを短時間で読み込むことができる。

Obsidianのvimのjump to linkで英単語だけでなく日本語でもジャンプしたい

最近Obsidianを使って個人の知識データベースを作っている。日々学んだこと・見た記事などをdaily noteにしつつ、ストックとなる記事を貯めていっている。 これまでもEvernote・Notionや個人ブログ等で似たことをやろうとしていたが、Obsidianはローカルで使うmarkdownのエディタとして普通に日々のメモツール(これまではSlackとかにメモしていた)の延長で使えるので、メモとストックの垣根を無くせるのが良くて、常用するツールになりそう。

エディタを快適に使うときに自分にとって欠かせない要素なのがvimキーバインドで、Obsidianにも公式にvimキーバインドがあるので使っている。vimの設定はあまりカスタマイズしないほうだが、ジャンプ機能を使いたいと思って、

📗vim-easymotionのように入力した文字から始まる単語にジャンプしたい - Minerva

ここで知ったjump to linkを入れた。 普段はjump to anywhereをよく使うが、デフォルトの設定の正規表現\b\w{3,}\bだと日本語の位置にジャンプできない。そこで日本語でも兼用できる正規表現にしたいといくつか試行錯誤した結果、[。、,.\s]\S{4}で自分にとって満足のいく結果が出るようになった。

超速で成果を出す アジャイル仕事術

たまたま手にとったので読んだ。

著者の方はソフトウェア開発のマネジメント経験があって、タイトルの「アジャイル」もソフトウェア開発の「アジャイル」の文脈に沿っている。 内容的には特別新しい観点が書かれているわけではないが、体系だてて整理して述べられている印象はあった。

本書の中では仕事術として重要なスキルとして「構想力」「俊敏力」「適応力」「連携力」「共創力」の5つが挙げられているが、自分は最後の「共創力」が特に弱いと感じる。直近4年間ほどで本業2社(サイバーエージェント、ナイルワークス)、副業7社の9つの会社で仕事をしてきた。どの会社でも、個人としてはそこそこアウトプットは出せる。だけどチームとして、異なる専門性を持った個人が集まった集団として、単なる個人のかけあわせ以上の仕事の成果が出せてきたかでいうとあまり実現できていない。 個人としてスキルを磨くだけではなくて、他人と共創して自分一人×時間では決してなし得ない仕事をできるようになりたいと思っている。 その課題感にあったヒントがあったように思った。 ポイントを要約すると「互いに興味を持ち、質より量で情報を共有しあい、対話によって価値観の違いを理解しあい、ビジョンと行動原則に落とし込むこと」と理解した。 リモートで最低限のタスク管理だけしているとこれは実現できない。